home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Blender 2.49b / blender-2.49b-windows.exe / $_4_ / .blender / scripts / wizard_curve2tree.py < prev    next >
Text File  |  2009-08-31  |  139KB  |  4,049 lines

  1. #!BPY
  2. """
  3. Name: 'Tree from Curves'
  4. Blender: 245
  5. Group: 'Wizards'
  6. Tip: 'Generate trees from curve shapes'
  7. """
  8.  
  9. __author__ = "Campbell Barton"
  10. __url__ = ['www.blender.org', 'blenderartists.org']
  11. __version__ = "0.1"
  12.  
  13. __bpydoc__ = """\
  14.  
  15. """
  16.  
  17. # --------------------------------------------------------------------------
  18. # Tree from Curves v0.1 by Campbell Barton (AKA Ideasman42)
  19. # --------------------------------------------------------------------------
  20. # ***** BEGIN GPL LICENSE BLOCK *****
  21. #
  22. # This program is free software; you can redistribute it and/or
  23. # modify it under the terms of the GNU General Public License
  24. # as published by the Free Software Foundation; either version 2
  25. # of the License, or (at your option) any later version.
  26. #
  27. # This program is distributed in the hope that it will be useful,
  28. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  29. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  30. # GNU General Public License for more details.
  31. #
  32. # You should have received a copy of the GNU General Public License
  33. # along with this program; if not, write to the Free Software Foundation,
  34. # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  35. #
  36. # ***** END GPL LICENCE BLOCK *****
  37. # --------------------------------------------------------------------------
  38.  
  39. import bpy
  40. import Blender
  41. import BPyMesh
  42. from Blender.Mathutils import Vector, Matrix, AngleBetweenVecs, LineIntersect, TranslationMatrix, ScaleMatrix, RotationMatrix, Rand
  43. from Blender.Geometry import ClosestPointOnLine
  44. from Blender.Noise import randuvec
  45.  
  46. GLOBALS = {}
  47. GLOBALS['non_bez_error'] = 0
  48.  
  49. '''
  50. def debugVec(v1,v2):
  51.     sce = bpy.data.scenes.active
  52.     me = bpy.data.meshes.new()
  53.     me.verts.extend( [v1,v2] )
  54.     me.edges.extend( [(0,1)] )
  55.     sce.objects.new(me)
  56. '''
  57.  
  58. def AngleBetweenVecsSafe(a1, a2):
  59.     try:
  60.         return AngleBetweenVecs(a1,a2)
  61.     except:
  62.         return 180.0
  63.  
  64. # Python 2.3 has no reversed.
  65. try:
  66.     reversed
  67. except:
  68.     def reversed(l): return l[::-1]
  69.  
  70. # Copied from blender, we could wrap this! - BKE_curve.c
  71. # But probably not toooo bad in python
  72. def forward_diff_bezier(q0, q1, q2, q3, pointlist, steps, axis):
  73.     f= float(steps)
  74.     rt0= q0
  75.     rt1= 3.0*(q1-q0)/f
  76.     f*= f
  77.     rt2= 3.0*(q0-2.0*q1+q2)/f
  78.     f*= steps
  79.     rt3= (q3-q0+3.0*(q1-q2))/f
  80.     
  81.     q0= rt0
  82.     q1= rt1+rt2+rt3
  83.     q2= 2*rt2+6*rt3
  84.     q3= 6*rt3
  85.     if axis == None:
  86.         for a in xrange(steps+1):
  87.             pointlist[a] = q0
  88.             q0+= q1
  89.             q1+= q2
  90.             q2+= q3;
  91.         
  92.     else:
  93.         for a in xrange(steps+1):
  94.             pointlist[a][axis] = q0
  95.             q0+= q1
  96.             q1+= q2
  97.             q2+= q3;
  98.  
  99. def points_from_bezier_seg(steps, pointlist, radlist, bez1_vec, bez2_vec, radius1, radius2):
  100.     
  101.     # x,y,z,axis
  102.     for ii in (0,1,2):
  103.         forward_diff_bezier(bez1_vec[1][ii], bez1_vec[2][ii],  bez2_vec[0][ii], bez2_vec[1][ii], pointlist, steps, ii)
  104.     
  105.     # radius - no axis, Copied from blenders BBone roll interpolation.
  106.     forward_diff_bezier(radius1, radius1 + 0.390464*(radius2-radius1), radius2 - 0.390464*(radius2-radius1),    radius2,    radlist, steps, None)
  107.  
  108.  
  109. def debug_pt(co):
  110.     Blender.Window.SetCursorPos(tuple(co))
  111.     Blender.Window.RedrawAll()
  112.     print 'debugging', co
  113.  
  114. def freshMesh(mesh):
  115.     '''
  116.     Utility function to get a new mesh or clear the existing one, but dont clear everything.
  117.     '''
  118.     if mesh:
  119.         materials = mesh.materials
  120.         mesh.verts = None
  121.         for group in mesh.getVertGroupNames():
  122.             mesh.removeVertGroup(group) 
  123.             
  124.         # Add materials back
  125.         mesh.materials = materials
  126.     else:
  127.         mesh = bpy.data.meshes.new()
  128.         
  129.     return mesh
  130.  
  131. def getObFromName(name):
  132.     if name:
  133.         try:    return bpy.data.objects[name]
  134.         except:    return None
  135.     else:
  136.         return None
  137.  
  138. def getGroupFromName(name):
  139.     if name:
  140.         try:    return bpy.data.groups[name]
  141.         except:    return None
  142.     else:
  143.         return None    
  144.  
  145. def closestVecIndex(vec, vecls):
  146.     best= -1
  147.     best_dist = 100000000
  148.     for i, vec_test in enumerate(vecls):
  149.         # Dont use yet, we may want to tho
  150.         if vec_test: # Seems odd, but use this so we can disable some verts in the list.
  151.             dist = (vec-vec_test).length
  152.             if dist < best_dist:
  153.                 best = i
  154.                 best_dist = dist
  155.     
  156.     return best
  157.  
  158. IRATIONAL_NUM = 22.0/7.0
  159. def next_random_num(rnd):
  160.     '''
  161.     return a random number between 0.0 and 1.0
  162.     '''
  163.     rnd[0] += (rnd[0] * IRATIONAL_NUM) % 1
  164.     # prevent 
  165.     if rnd[0] > 1000000:
  166.         rnd[0]-=1000000
  167.     return rnd[0] % 1
  168.  
  169. eul = 0.00001
  170.  
  171. BRANCH_TYPE_CURVE = 0
  172. BRANCH_TYPE_GROWN = 1
  173. BRANCH_TYPE_FILL = 2
  174.  
  175. class tree:
  176.     def __init__(self):
  177.         self.branches_all =        []
  178.         self.branches_root =    []
  179.         self.branches_twigs =    []
  180.         self.mesh = None
  181.         self.armature = None
  182.         self.objectCurve = None
  183.         self.objectCurveMat = None
  184.         self.objectCurveIMat = None
  185.         
  186.         self.objectTwigBounds = None # use for twigs only at the moment.
  187.         self.objectTwigBoundsIMat = None
  188.         self.objectTwigBoundsMat = None
  189.         self.objectTwigBoundsMesh = None
  190.         
  191.         self.objectLeafBounds = None
  192.         self.objectLeafBoundsIMat = None
  193.         self.objectLeafBoundsMesh = None
  194.         
  195.         self.limbScale = 1.0
  196.         
  197.         self.debug_objects = []
  198.         self.steps = 6 # defalt, curve overwrites
  199.     
  200.     def __repr__(self):
  201.         s = ''
  202.         s += '[Tree]'
  203.         s += '  limbScale: %.6f' % self.limbScale
  204.         s += '  object: %s' % self.objectCurve
  205.         
  206.         for brch in self.branches_root:
  207.             s += str(brch)
  208.         return s
  209.     
  210.     def fromCurve(self, objectCurve):
  211.         # Now calculate the normals
  212.         self.objectCurve = objectCurve
  213.         self.objectCurveMat = objectCurve.matrixWorld
  214.         self.objectCurveIMat = self.objectCurveMat.copy().invert()
  215.         curve = objectCurve.data
  216.         self.steps = curve.resolu # curve resolution
  217.         
  218.         # Set the curve object scale
  219.         if curve.bevob:
  220.             # A bit of a hack to guess the size of the curve object if you have one.
  221.             bb = curve.bevob.boundingBox
  222.             # self.limbScale = (bb[0] - bb[7]).length / 2.825 # THIS IS GOOD WHEN NON SUBSURRFED
  223.             self.limbScale = (bb[0] - bb[7]).length / 1.8
  224.         elif curve.ext2 != 0.0:
  225.             self.limbScale = curve.ext2 * 1.5
  226.             
  227.         # forward_diff_bezier will fill in the blanks
  228.         # nice we can reuse these for every curve segment :)
  229.         pointlist = [[None, None, None] for i in xrange(self.steps+1)]
  230.         radlist = [ None for i in xrange(self.steps+1) ]
  231.         
  232.         for spline in curve:
  233.             
  234.             if len(spline) < 2: # Ignore single point splines
  235.                 continue
  236.             
  237.             if spline.type != 1: # 0 poly, 1 bez, 4 nurbs
  238.                 GLOBALS['non_bez_error'] = 1
  239.                 continue
  240.             
  241.                 
  242.             brch = branch()
  243.             brch.type = BRANCH_TYPE_CURVE
  244.             
  245.             
  246.             
  247.             bez_list = list(spline)
  248.             for i in xrange(1, len(bez_list)):
  249.                 bez1 = bez_list[i-1]
  250.                 bez2 = bez_list[i]
  251.                 vec1 = bez1.vec
  252.                 vec2 = bez2.vec
  253.                 if abs(vec1[1][0]-vec2[1][0]) > 0.000001 or\
  254.                    abs(vec1[1][1]-vec2[1][1]) > 0.000001 or\
  255.                    abs(vec1[1][2]-vec2[1][2]) > 0.000001:
  256.  
  257.                     points_from_bezier_seg(self.steps, pointlist, radlist, vec1, vec2, bez1.radius, bez2.radius)
  258.                 
  259.                     # remove endpoint for all but the last
  260.                     len_pointlist = len(pointlist)
  261.                     if i != len(bez_list)-1:
  262.                         len_pointlist -= 1
  263.                     
  264.                     brch.bpoints.extend([ bpoint(brch, Vector(pointlist[ii]), Vector(), radlist[ii] * self.limbScale) for ii in xrange(len_pointlist) ])
  265.             
  266.             # Finalize once point data is there
  267.             if brch.bpoints:
  268.                 # if all points are in the same location, this is possible
  269.                 self.branches_all.append(brch)
  270.                 if brch.bpoints[0].radius < brch.bpoints[-1].radius: # This means we dont have to worry about curve direction.
  271.                     brch.bpoints.reverse()
  272.                 brch.calcData()
  273.             
  274.         # Sort from big to small, so big branches get priority
  275.         # Py 2.3 dosnt have keywords in sort
  276.         try:    self.branches_all.sort( key = lambda brch: -brch.bpoints[0].radius )
  277.         except: self.branches_all.sort( lambda brch_a, brch_b: cmp(brch_b.bpoints[0].radius, brch_a.bpoints[0].radius) ) # py2.3
  278.     
  279.     
  280.     def closestBranchPt(self, co):
  281.         best_brch = None
  282.         best_pt = None
  283.         best_dist = 10000000000
  284.         for brch in self.branches_all:
  285.             for pt in brch.bpoints:
  286.                 # if pt.inTwigBounds: # only find twigs, give different results for leaves
  287.                 l = (pt.co-co).length
  288.                 if l < best_dist:
  289.                     best_dist = l
  290.                     best_brch = brch
  291.                     best_pt = pt
  292.         return best_brch, best_pt
  293.     
  294.     def setTwigBounds(self, objectMesh):
  295.         self.objectTwigBounds = objectMesh
  296.         self.objectTwigBoundsMesh = objectMesh.getData(mesh=1)
  297.         self.objectTwigBoundsMat = objectMesh.matrixWorld.copy()
  298.         self.objectTwigBoundsIMat = self.objectTwigBoundsMat.copy().invert()
  299.         
  300.         for brch in self.branches_all:
  301.             brch.calcTwigBounds(self)
  302.             
  303.     def setLeafBounds(self, objectMesh):
  304.         self.objectLeafBounds = objectMesh
  305.         self.objectLeafBoundsMesh = objectMesh.getData(mesh=1)
  306.         self.objectLeafBoundsIMat = objectMesh.matrixWorld.copy().invert()
  307.     
  308.     def isPointInTwigBounds(self, co, selected_only=False):
  309.         return self.objectTwigBoundsMesh.pointInside(co * self.objectCurveMat * self.objectTwigBoundsIMat, selected_only)
  310.  
  311.     def isPointInLeafBounds(self, co, selected_only=False):
  312.         return self.objectLeafBoundsMesh.pointInside(co * self.objectCurveMat * self.objectLeafBoundsIMat, selected_only)
  313.  
  314.     def resetTags(self, value):
  315.         for brch in self.branches_all:
  316.             brch.tag = value
  317.     
  318.     def buildConnections(    self,\
  319.                             sloppy = 1.0,\
  320.                             connect_base_trim = 1.0,\
  321.                             do_twigs = False,\
  322.                             twig_ratio = 2.0,\
  323.                             twig_select_mode = 0,\
  324.                             twig_select_factor = 0.5,\
  325.                             twig_scale = 0.8,\
  326.                             twig_scale_width = 1.0,\
  327.                             twig_random_orientation = 180,\
  328.                             twig_random_angle = 33,\
  329.                             twig_recursive=True,\
  330.                             twig_recursive_limit=3,\
  331.                             twig_ob_bounds=None,\
  332.                             twig_ob_bounds_prune=True,\
  333.                             twig_ob_bounds_prune_taper=1.0,\
  334.                             twig_placement_maxradius=10.0,\
  335.                             twig_placement_maxtwig=0,\
  336.                             twig_follow_parent=0.0,\
  337.                             twig_follow_x=0.0,\
  338.                             twig_follow_y=0.0,\
  339.                             twig_follow_z=0.0,\
  340.                             do_variation = 0,\
  341.                             variation_seed = 1,\
  342.                             variation_orientation = 0.0,\
  343.                             variation_scale = 0.0,\
  344.                             do_twigs_fill = 0,\
  345.                             twig_fill_levels=4,\
  346.                             twig_fill_rand_scale=0.0,\
  347.                             twig_fill_fork_angle_max=180.0,\
  348.                             twig_fill_radius_min=0.1,\
  349.                             twig_fill_radius_factor=0.75,\
  350.                             twig_fill_shape_type=0,\
  351.                             twig_fill_shape_rand=0.0,\
  352.                             twig_fill_shape_power=0.3,\
  353.                         ):
  354.         '''
  355.         build tree data - fromCurve must run first
  356.         '''
  357.         
  358.         
  359.         # Sort the branchs by the first radius, so big branchs get joins first
  360.         ### self.branches_all.sort( key = lambda brch: brch.bpoints[0].radius )
  361.         
  362.         #self.branches_all.reverse()
  363.         
  364.         # Connect branches
  365.         for i in xrange(len(self.branches_all)):
  366.             brch_i = self.branches_all[i]
  367.             
  368.             for j in xrange(len(self.branches_all)):
  369.                 if i != j:
  370.                     # See if any of the points match this branch
  371.                     # see if Branch 'i' is the child of branch 'j'
  372.                     
  373.                     brch_j = self.branches_all[j]
  374.                     
  375.                     if not brch_j.inParentChain(brch_i): # So we dont make cyclic tree!
  376.                         
  377.                         pt_best_j, dist = brch_j.findClosest(brch_i.bpoints[0].co)
  378.                         
  379.                         # Check its in range, allow for a bit out - hense the sloppy
  380.                         # The second check in the following IF was added incase the point is close enough to the line but the midpoint is further away
  381.                         # ...in this case the the resulting mesh will be adjusted to fit the join so its best to make it.
  382.                         if     (dist <                                            pt_best_j.radius * sloppy)  or \
  383.                             ((brch_i.bpoints[0].co - pt_best_j.co).length <    pt_best_j.radius * sloppy):
  384.                             
  385.                             
  386.                             brch_i.parent_pt = pt_best_j
  387.                             pt_best_j.childCount += 1 # dont remove me
  388.                             
  389.                             brch_i.baseTrim(connect_base_trim)
  390.                             
  391.                             '''
  392.                             if pt_best_j.childCount>4:
  393.                                 raise "ERROR"
  394.                             '''
  395.                             
  396.                             # addas a member of best_j.children later when we have the geometry info available.
  397.                             
  398.                             #### print "Found Connection!!!", i, j
  399.                             break # go onto the next branch
  400.         
  401.         """
  402.             children = [brch_child for brch_child in pt.children]
  403.             if children:
  404.                 # This pt is one side of the segment, pt.next joins this segment.
  405.                 # calculate the median point the 2 segments would spanal
  406.                 # Once this is done we need to adjust 2 things
  407.                 # 1) move both segments up/down so they match the branches best.
  408.                 # 2) set the spacing of the segments around the point.
  409.                 
  410.         
  411.         # First try to get the ideal some space around each joint
  412.         # the spacing shoule be an average of 
  413.         for brch.bpoints:
  414.         """
  415.         
  416.         '''
  417.         for brch in self.branches_all:
  418.             brch.checkPointList()
  419.         '''
  420.         
  421.         # Variations - use for making multiple versions of the same tree.
  422.         if do_variation:
  423.             irational_num = 22.0/7.0 # use to make the random number more odd
  424.             rnd = [variation_seed]
  425.             
  426.             # Add children temporarily
  427.             for brch in self.branches_all:
  428.                 if brch.parent_pt:
  429.                     rnd_rot = ((next_random_num(rnd) * variation_orientation) - 0.5) * 720
  430.                     mat_orientation = RotationMatrix(rnd_rot, 3, 'r', brch.parent_pt.no)
  431.                     rnd_sca = 1 + ((next_random_num(rnd)-0.5)* variation_scale )
  432.                     mat_scale = Matrix([rnd_sca,0,0],[0,rnd_sca,0],[0,0,rnd_sca])
  433.                     # mat_orientation = RotationMatrix(0, 3, 'r', brch.parent_pt.no)
  434.                     brch.transformRecursive(self, mat_scale * mat_orientation, brch.parent_pt.co)
  435.         
  436.         if (do_twigs or do_twigs_fill) and twig_ob_bounds: # Only spawn twigs inside this mesh
  437.             self.setTwigBounds(twig_ob_bounds)
  438.         
  439.         # Important we so this with existing parent/child but before connecting and calculating verts.
  440.         if do_twigs:
  441.             
  442.             # scale values down
  443.             twig_random_orientation= twig_random_orientation/360.0
  444.             twig_random_angle= twig_random_angle/360.0
  445.             
  446.             irational_num = 22.0/7.0 # use to make the random number more odd
  447.             
  448.             if not twig_recursive:
  449.                 twig_recursive_limit = 0
  450.             
  451.             self.buildTwigs(twig_ratio, twig_select_mode, twig_select_factor)
  452.             
  453.             branches_twig_attached = []
  454.             
  455.             # This wont add all! :/
  456.             brch_twig_index = 0
  457.             brch_twig_index_LAST = -1 # use this to prevent in inf loop, since its possible we cant place every branch
  458.             while brch_twig_index < len(self.branches_twigs) and brch_twig_index_LAST != brch_twig_index:
  459.                 ###print "While"
  460.                 ### print brch_twig_index, len(self.branches_twigs) # if this dosnt change, quit the while
  461.                 
  462.                 brch_twig_index_LAST = brch_twig_index
  463.                 
  464.                 # new twigs have been added, recalculate
  465.                 branches_twig_sort = [brch.bestTwigSegment() for brch in self.branches_all]
  466.                 branches_twig_sort.sort() # this will sort the branches with best braches for adding twigs to at the start of the list
  467.                 
  468.                 for tmp_sortval, twig_pt_index, brch_parent in branches_twig_sort: # tmp_sortval is not used.
  469.                     if        twig_pt_index != -1 and \
  470.                             (twig_recursive_limit == 0 or brch_parent.generation < twig_recursive_limit) and \
  471.                             (twig_placement_maxtwig == 0 or brch_parent.twig_count < twig_placement_maxtwig) and \
  472.                             brch_parent.bpoints[twig_pt_index].radius < twig_placement_maxradius:
  473.                         
  474.                         if brch_twig_index >= len(self.branches_twigs):
  475.                             break
  476.                         
  477.                         brch_twig = self.branches_twigs[brch_twig_index]
  478.                         parent_pt = brch_parent.bpoints[twig_pt_index]
  479.                         
  480.                         brch_twig.parent_pt = parent_pt
  481.                         parent_pt.childCount += 1
  482.                         
  483.                         # Scale this twig using this way...
  484.                         # The size of the parent, scaled by the parent point's radius,
  485.                         # ...compared to the parent branch;s root point radius.
  486.                         # Also take into account the length of the parent branch
  487.                         # Use this for pretend random numbers too.
  488.                         scale = twig_scale * (parent_pt.branch.bpoints[0].radius / brch_twig.bpoints[0].radius) * (parent_pt.radius / parent_pt.branch.bpoints[0].radius)
  489.                         
  490.                         # Random orientation
  491.                         # THIS IS NOT RANDOM - Dont be real random so we can always get re-produceale results.
  492.                         if twig_random_orientation:    rnd1 = (((irational_num * scale * 10000000) % 360) - 180) * twig_random_orientation
  493.                         else:                        rnd1 = 0.0
  494.                         if twig_random_angle:        rnd2 = (((irational_num * scale * 66666666) % 360) - 180) * twig_random_angle
  495.                         else:                        rnd2 = 0.0
  496.                         
  497.                         # Align this with the existing branch
  498.                         angle = AngleBetweenVecsSafe(zup, parent_pt.no)
  499.                         cross = zup.cross(parent_pt.no)
  500.                         mat_align = RotationMatrix(angle, 3, 'r', cross)
  501.                         
  502.                         # Use the bend on the point to work out which way to make the branch point!
  503.                         if parent_pt.prev:    cross = parent_pt.no.cross(parent_pt.prev.no - parent_pt.no)
  504.                         else:                cross = parent_pt.no.cross(parent_pt.next.no - parent_pt.no)
  505.                         
  506.                         if parent_pt.branch.parent_pt:
  507.                             angle = AngleBetweenVecsSafe(parent_pt.branch.parent_pt.no, parent_pt.no)
  508.                         else:
  509.                             # Should add a UI for this... only happens when twigs come off a root branch
  510.                             angle = 66
  511.                         
  512.                         mat_branch_angle = RotationMatrix(angle+rnd1, 3, 'r', cross)
  513.                         mat_scale = Matrix([scale,0,0],[0,scale,0],[0,0,scale])
  514.                         
  515.                         mat_orientation = RotationMatrix(rnd2, 3, 'r', parent_pt.no)
  516.                         
  517.                         if twig_scale_width != 1.0:
  518.                             # adjust length - no radius adjusting
  519.                             for pt in brch_twig.bpoints:
  520.                                 pt.radius *= twig_scale_width
  521.                         
  522.                         brch_twig.transform(mat_scale * mat_branch_angle * mat_align * mat_orientation, parent_pt.co)
  523.                         
  524.                         # Follow the parent normal
  525.                         if twig_follow_parent or twig_follow_x or twig_follow_y or twig_follow_z:
  526.                             
  527.                             vecs = []
  528.                             brch_twig_len = float(len(brch_twig.bpoints))
  529.                             
  530.                             if twig_follow_parent:
  531.                                 no = parent_pt.no.copy() * twig_follow_parent
  532.                             else:
  533.                                 no = Vector()
  534.                             
  535.                             no.x += twig_follow_x
  536.                             no.y += twig_follow_y
  537.                             no.z += twig_follow_z
  538.                             
  539.                             for i, pt in enumerate(brch_twig.bpoints):
  540.                                 if pt.prev:
  541.                                     fac = i / brch_twig_len
  542.                                     
  543.                                     # Scale this value
  544.                                     fac_inv = 1-fac
  545.                                     
  546.                                     no_orig = pt.co - pt.prev.co
  547.                                     len_orig = no_orig.length
  548.                                     
  549.                                     no_new = (fac_inv * no_orig) + (fac * no)
  550.                                     no_new.length = len_orig
  551.                                     
  552.                                     # Mix the 2 normals
  553.                                     vecs.append(no_new)
  554.                                     
  555.                             # Apply the coords
  556.                             for i, pt in enumerate(brch_twig.bpoints):
  557.                                 if pt.prev:
  558.                                     pt.co = pt.prev.co + vecs[i-1]
  559.                             
  560.                             brch_twig.calcPointExtras()
  561.                         
  562.                         
  563.                         # When using a bounding mesh, clip and calculate points in bounds.
  564.                         #print "Attempting to trim base"
  565.                         brch_twig.baseTrim(connect_base_trim)
  566.                         
  567.                         if twig_ob_bounds and (twig_ob_bounds_prune or twig_recursive):
  568.                             brch_twig.calcTwigBounds(self)
  569.                         
  570.                             # we would not have been but here if the bounds were outside
  571.                             if twig_ob_bounds_prune:
  572.                                 brch_twig.boundsTrim()
  573.                                 if twig_ob_bounds_prune_taper != 1.0:
  574.                                     # taper to a point. we could use some nice taper algo here - just linear atm.
  575.                                     
  576.                                     brch_twig.taper(twig_ob_bounds_prune_taper)
  577.                         
  578.                         # Make sure this dosnt mess up anything else
  579.                         
  580.                         brch_twig_index += 1
  581.                         
  582.                         # Add to the branches
  583.                         #self.branches_all.append(brch_twig)
  584.                         if len(brch_twig.bpoints) > 2:
  585.                             branches_twig_attached.append(brch_twig)
  586.                             brch_twig.generation = brch_parent.generation + 1
  587.                             brch_parent.twig_count += 1
  588.                         else:
  589.                             # Dont add the branch
  590.                             parent_pt.childCount -= 1
  591.                 
  592.                 # Watch This! - move 1 tab down for no recursive twigs
  593.                 if twig_recursive:
  594.                     self.branches_all.extend(branches_twig_attached)
  595.                     branches_twig_attached = []
  596.             
  597.             if not twig_recursive:
  598.                 self.branches_all.extend(branches_twig_attached)
  599.                 branches_twig_attached = []
  600.         
  601.         
  602.         if do_twigs_fill and twig_ob_bounds:
  603.             self.twigFill(\
  604.                 twig_fill_levels,\
  605.                 twig_fill_rand_scale,\
  606.                 twig_fill_fork_angle_max,\
  607.                 twig_fill_radius_min,\
  608.                 twig_fill_radius_factor,\
  609.                 twig_fill_shape_type,\
  610.                 twig_fill_shape_rand,\
  611.                 twig_fill_shape_power,\
  612.             )
  613.         
  614.         ### self.branches_all.sort( key = lambda brch: brch.parent_pt != None )
  615.         
  616.         # Calc points with dependancies
  617.         # detect circular loops!!! - TODO
  618.         #### self.resetTags(False) # NOT NEEDED NOW
  619.         done_nothing = False
  620.         while done_nothing == False:
  621.             done_nothing = True
  622.             
  623.             for brch in self.branches_all:
  624.                 
  625.                 if brch.tag == False and (brch.parent_pt == None or brch.parent_pt.branch.tag == True):
  626.                     # Assign this to a spesific side of the parents point
  627.                     # we know this is a child but not which side it should be attached to.
  628.                     if brch.parent_pt:
  629.                         
  630.                         child_locs = [\
  631.                         brch.parent_pt.childPointUnused(0),\
  632.                         brch.parent_pt.childPointUnused(1),\
  633.                         brch.parent_pt.childPointUnused(2),\
  634.                         brch.parent_pt.childPointUnused(3)]
  635.                         
  636.                         best_idx = closestVecIndex(brch.bpoints[0].co, child_locs)
  637.                         
  638.                         # best_idx could be -1 if all childPoint's are used however we check for this and dont allow it to happen.
  639.                         #if best_idx==-1:
  640.                         #    raise "Error"z
  641.                         brch.parent_pt.children[best_idx] = brch
  642.                     
  643.                     for pt in brch.bpoints:
  644.                         pt.calcVerts()
  645.                     
  646.                     done_nothing = False
  647.                     brch.tag = True
  648.         
  649.         '''
  650.         for i in xrange(len(self.branches_all)):
  651.             brch_i = self.branches_all[i]
  652.             print brch_i.myindex,
  653.             print 'tag', brch_i.tag,
  654.             print 'parent is',
  655.             if brch_i.parent_pt:
  656.                 print brch_i.parent_pt.branch.myindex
  657.             else:
  658.                 print None
  659.         '''
  660.     
  661.     def optimizeSpacing(self, seg_density=0.5, seg_density_angle=20.0, seg_density_radius=0.3, joint_compression=1.0, joint_smooth=1.0):
  662.         '''
  663.         Optimize spacing, taking branch hierarchy children into account,
  664.         can add or subdivide segments so branch joins dont look horrible.
  665.         '''
  666.         for brch in self.branches_all:
  667.             brch.evenJointDistrobution(joint_compression)
  668.         
  669.         # Correct points that were messed up from sliding
  670.         # This happens when one point is pushed past another and the branch gets an overlaping line
  671.         
  672.         for brch in self.branches_all:
  673.             brch.fixOverlapError(joint_smooth)
  674.         
  675.         
  676.         # Collapsing
  677.         for brch in self.branches_all:
  678.             brch.collapsePoints(seg_density, seg_density_angle, seg_density_radius, joint_smooth)
  679.             
  680.         '''
  681.         for brch in self.branches_all:
  682.             brch.branchReJoin()
  683.         '''
  684.     
  685.     def twigFill(self_tree,\
  686.             twig_fill_levels,\
  687.             twig_fill_rand_scale,\
  688.             twig_fill_fork_angle_max,\
  689.             twig_fill_radius_min,\
  690.             twig_fill_radius_factor,\
  691.             twig_fill_shape_type,\
  692.             twig_fill_shape_rand,\
  693.             twig_fill_shape_power,\
  694.         ):
  695.         '''
  696.         Fill with twigs, this function uses its own class 'segment'
  697.         
  698.         twig_fill_shape_type;
  699.             0 - no child smoothing
  700.             1 - smooth one child
  701.             2 - smooth both children
  702.         
  703.         '''
  704.         
  705.         rnd = [1]
  706.         
  707.         segments_all = []
  708.         segments_level = []
  709.         
  710.         # Only for testing
  711.         def preview_curve():
  712.             TWIG_WIDTH_MAX = 1.0
  713.             TWIG_WIDTH_MIN = 0.1
  714.             cu = bpy.data.curves["cu"]
  715.             # remove all curves
  716.             while len(cu):
  717.                 del cu[0]
  718.             # return
  719.             
  720.             cu.setFlag(1)
  721.             cu.ext2 = 0.01
  722.             
  723.             WIDTH_STEP = (TWIG_WIDTH_MAX-TWIG_WIDTH_MIN) / twig_fill_levels
  724.             
  725.             for i, seg in enumerate(segments_all):
  726.                 
  727.                 # 1 is the base and 2 is the tail
  728.                 
  729.                 p1_h2 = seg.getHeadHandle() # isnt used
  730.                 p1_co = seg.headCo
  731.                 p1_h1 = seg.getHeadHandle()
  732.                 
  733.                 p2_h1 = seg.getTailHandle()
  734.                 
  735.                 p2_co = seg.tailCo
  736.                 p2_h2 = seg.tailCo # isnt used
  737.                 
  738.                 bez1 = Blender.BezTriple.New([ p1_h1[0], p1_h1[1], p1_h1[2], p1_co[0], p1_co[1], p1_co[2], p1_h2[0], p1_h2[1], p1_h2[2] ])
  739.                 bez2 = Blender.BezTriple.New([ p2_h1[0], p2_h1[1], p2_h1[2], p2_co[0], p2_co[1], p2_co[2], p2_h2[0], p2_h2[1], p2_h2[2] ])
  740.                 bez1.handleTypes = bez2.handleTypes = [Blender.BezTriple.HandleTypes.FREE, Blender.BezTriple.HandleTypes.FREE]
  741.                 
  742.                 bez1.radius = TWIG_WIDTH_MIN + (WIDTH_STEP * (seg.levelFromLeaf+1))
  743.                 bez2.radius = TWIG_WIDTH_MIN + (WIDTH_STEP * seg.levelFromLeaf)
  744.                 
  745.                 cunurb = cu.appendNurb(bez1)
  746.                 cunurb.append(bez2)
  747.                 
  748.                 # This sucks
  749.                 for bez in cunurb:
  750.                     bez.handleTypes = [Blender.BezTriple.HandleTypes.FREE, Blender.BezTriple.HandleTypes.FREE]
  751.             
  752.             ### cc = sce.objects.new( cu )
  753.             cu.update()
  754.         
  755.         
  756.         def mergeCo(parentCo, ch1Co, ch2Co, twig_fill_shape_rand):
  757.             if twig_fill_shape_rand==0.0:
  758.                 return (parentCo + ch1Co + ch2Co) / 3.0
  759.             else:
  760.                 
  761.                 w1 = (next_random_num(rnd)*twig_fill_shape_rand) + (1-twig_fill_shape_rand)
  762.                 w2 = (next_random_num(rnd)*twig_fill_shape_rand) + (1-twig_fill_shape_rand)
  763.                 w3 = (next_random_num(rnd)*twig_fill_shape_rand) + (1-twig_fill_shape_rand)
  764.                 wtot = w1+w2+w3
  765.                 w1=w1/wtot
  766.                 w2=w2/wtot
  767.                 w3=w3/wtot
  768.                 
  769.                 # return (parentCo*w1 + ch1Co*w2 + ch2Co*w2)
  770.                 co1 = (parentCo * w1)    + (ch1Co * (1.0-w1))
  771.                 co2 = (ch1Co * w2)        + (ch2Co * (1.0-w2))
  772.                 co3 = (ch2Co * w3)        + (parentCo * (1.0-w3))
  773.                 
  774.                 return (co1 + co2 + co3) / 3.0
  775.                 
  776.                 
  777.         
  778.         class segment:
  779.             def __init__(self, level):
  780.                 self.headCo = Vector()
  781.                 self.tailCo = Vector()
  782.                 self.parent = None
  783.                 self.mergeCount = 0
  784.                 self.levelFromLeaf = level # how far we are from the leaf in levels
  785.                 self.levelFromRoot = -1 # set later, assume root bone
  786.                 self.children = []
  787.                 segments_all.append(self)
  788.                 
  789.                 if level >= len(segments_level):    segments_level.append([self])
  790.                 else:                                segments_level[level].append(self)
  791.                 
  792.                 self.brothers = []
  793.                 self.no = Vector() # only endpoints have these
  794.                 # self.id = len(segments_all)
  795.                 
  796.                 # First value is the bpoint,
  797.                 # Second value is what to do -
  798.                 #  0 - dont join
  799.                 #  1 - Join to parent (tree point)
  800.                 #  2 - join to parent, point from another fill-twig branch we just created.
  801.                 
  802.                 self.bpt = (None, False) # branch point for root segs only
  803.                 self.new_bpt = None
  804.                 
  805.                 self.used = False # use this to tell if we are apart of a branch
  806.             
  807.             def sibling(self):
  808.                 i = self.parent.children.index(self)
  809.                 
  810.                 if i == 0:
  811.                     return self.parent.children[ 1 ]
  812.                 elif i == 1:
  813.                     return self.parent.children[ 0 ]
  814.                 else:
  815.                     raise "error"
  816.                     
  817.             
  818.             def getHeadHandle(self):
  819.                 """
  820.                 For Bezier only
  821.                 """
  822.                 
  823.                 if not self.parent:
  824.                     return self.headCo
  825.                 
  826.                 if twig_fill_shape_type == 0: # no smoothing
  827.                     return self.headCo
  828.                 elif twig_fill_shape_type == 1:
  829.                     if self.parent.children[1] == self:
  830.                         return self.headCo
  831.                 # 2 - always do both
  832.                 
  833.                 
  834.                 # Y shape with curve? optional
  835.                 
  836.                 # we have a parent but it has no handle direction, easier
  837.                 if not self.parent.parent:    no = self.parent.headCo - self.parent.tailCo
  838.                 else:                        no = self.parent.parent.headCo-self.parent.tailCo
  839.                 
  840.                 no.length =  self.getLength() * twig_fill_shape_power
  841.                 # Ok we have to account for the parents handle
  842.                 return self.headCo - no
  843.                 # return self.headCo - Vector(1, 0,0)
  844.             
  845.             def getTailHandle(self):
  846.                 """
  847.                 For Bezier only
  848.                 """
  849.                 if self.parent:
  850.                     no = self.parent.headCo-self.tailCo
  851.                     no.length = self.getLength() * twig_fill_shape_power
  852.                     return self.tailCo + no
  853.                 else:
  854.                     return self.tailCo # isnt used
  855.             
  856.             def getRootSeg(self):
  857.                 seg = self
  858.                 while seg.parent:
  859.                     seg = seg.parent
  860.                 
  861.                 return seg
  862.             
  863.             def calcBrothers(self):
  864.                 # Run on children first
  865.                 self.brothers.extend( \
  866.                     [seg_child_sibling.parent \
  867.                         for seg_child in self.children \
  868.                         for seg_child_sibling in seg_child.brothers \
  869.                         if seg_child_sibling.parent not in (self, None)]\
  870.                     )
  871.                     #print self.brothers
  872.             
  873.             def calcLevelFromRoot(self):
  874.                 if self.parent:
  875.                     self.levelFromRoot = self.parent.levelFromRoot + 1
  876.                 
  877.                 for seg_child in self.children:
  878.                     seg_child.calcLevelFromRoot()
  879.                     
  880.             # Dont use for now, but scale worked, transform was never tested.
  881.             """
  882.             def transform(self, matrix):
  883.                 self.headCo = self.headCo * matrix
  884.                 self.tailCo = self.tailCo * matrix
  885.                 
  886.                 if self.children:
  887.                     ch1 = self.children[0]
  888.                     ch2 = self.children[1]
  889.                     
  890.                     ch1.transform(matrix)
  891.                     ch2.transform(matrix)
  892.             
  893.             def scale(self, scale, cent=None):
  894.                 # scale = 0.9
  895.                 #matrix = Matrix([scale,0,0],[0,scale,0],[0,0,scale]).resize4x4()
  896.                 #self.transform(matrix)
  897.                 if cent == None: # first iter
  898.                     cent = self.headCo
  899.                     self.tailCo = ((self.tailCo-cent) * scale) + cent
  900.                 else:
  901.                     self.headCo = ((self.headCo-cent) * scale) + cent
  902.                     self.tailCo = ((self.tailCo-cent) * scale) + cent
  903.                 
  904.                 if self.children:
  905.                     self.children[0].scale(scale, cent)
  906.                     self.children[1].scale(scale, cent)
  907.             """
  908.             def recalcChildLoc(self):
  909.                 if not self.children:
  910.                     return
  911.                 ch1 = self.children[0]
  912.                 ch2 = self.children[1]
  913.                 new_mid = mergeCo(self.headCo, ch1.tailCo, ch2.tailCo, twig_fill_shape_rand)
  914.                 
  915.                 self.tailCo[:] = ch1.headCo[:] = ch2.headCo[:] = new_mid
  916.                 
  917.                 ch1.recalcChildLoc()
  918.                 ch2.recalcChildLoc()
  919.             
  920.             def merge(self, other):
  921.                 """
  922.                 Merge other into self and make a new segment
  923.                 """
  924.                 """
  925.                 seg_child = segment(self.levelFromLeaf)
  926.                 self.levelFromLeaf += 1
  927.                 
  928.                 seg_child.parent = other.parent = self
  929.                 
  930.                 # No need, recalcChildLoc sets the other coords
  931.                 #self.parent.tailCo = (self.headCo + self.tailCo + other.tailCo) / 3.0
  932.                 #self.parent.headCo[:] = self.headCo
  933.                 
  934.                 seg_child.headCo[:] = self.headCo
  935.                 
  936.                 # isect = LineIntersect(self.headCo, self.tailCo, other.headCo, other.tailCo)
  937.                 # new_head = (isect[0]+isect[1]) * 0.5
  938.                 
  939.                 seg_child.mergeCount += 1
  940.                 other.mergeCount += 1
  941.                 
  942.                 self.children.extend([ seg_child, other ])
  943.                 
  944.                 self.recalcChildLoc()
  945.                 
  946.                 # print 'merging', self.id, other.id
  947.                 """
  948.                 
  949.                 #new_head = (self.headCo + self.tailCo + other.headCo + other.tailCo) * 0.25
  950.                 
  951.                 self.parent = other.parent = segment(self.levelFromLeaf + 1)
  952.                 
  953.                 # No need, recalcChildLoc sets the self.parent.tailCo
  954.                 # self.parent.tailCo = (self.headCo + self.tailCo + other.tailCo) / 3.0
  955.                 
  956.                 self.parent.headCo[:] = self.headCo
  957.                 self.parent.bpt = self.bpt
  958.                 self.bpt = (None, False)
  959.                 
  960.                 # isect = LineIntersect(self.headCo, self.tailCo, other.headCo, other.tailCo)
  961.                 # new_head = (isect[0]+isect[1]) * 0.5
  962.                 
  963.                 self.mergeCount += 1
  964.                 other.mergeCount += 1
  965.                 
  966.                 self.parent.children.extend([ self, other ])
  967.                 
  968.                 self.parent.recalcChildLoc()
  969.                 # print 'merging', self.id, other.id
  970.                 
  971.                 
  972.             def findBestMerge(self, twig_fill_fork_angle_max):
  973.                 # print "findBestMerge"
  974.                 if self.parent != None:
  975.                     return
  976.                 
  977.                 best_dist = 1000000
  978.                 best_seg = None
  979.                 for seg_list in (self.brothers, segments_level[self.levelFromLeaf]):
  980.                     #for seg_list in (segments_level[self.levelFromLeaf],):
  981.                     
  982.                     # only use all other segments if we cant find any from our brothers
  983.                     if seg_list == segments_level[self.levelFromLeaf] and best_seg != None:
  984.                         break
  985.                     
  986.                     for seg in seg_list:
  987.                         # 2 ppoint join 
  988.                         if seg != self and seg.mergeCount == 0 and seg.parent == None:
  989.                             
  990.                             # find the point they would join    
  991.                             test_dist = (self.tailCo - seg.tailCo).length
  992.                             if test_dist < best_dist:
  993.                                 if twig_fill_fork_angle_max > 179:
  994.                                     best_dist = test_dist
  995.                                     best_seg = seg
  996.                                 else:
  997.                                     # Work out if the desired angle range is ok.
  998.                                     mco = mergeCo( self.headCo, self.tailCo, seg.tailCo, 0.0 ) # we dont want the random value for this test
  999.                                     ang = AngleBetweenVecsSafe(self.tailCo-mco, seg.tailCo-mco)
  1000.                                     if ang < twig_fill_fork_angle_max:
  1001.                                         best_dist = test_dist
  1002.                                         best_seg = seg
  1003.                 return best_seg
  1004.             
  1005.             def getNormal(self):
  1006.                 return (self.headCo - self.tailCo).normalize()
  1007.             
  1008.             def getLength(self):
  1009.                 return (self.headCo - self.tailCo).length
  1010.             """
  1011.             def toMatrix(self, LEAF_SCALE, LEAF_RANDSCALE, LEAF_RANDVEC):
  1012.                 if LEAF_RANDSCALE:    scale = LEAF_SCALE * Rand(1.0-LEAF_RANDSCALE, 1.0+LEAF_RANDSCALE)
  1013.                 else:                scale = LEAF_SCALE * 1.0
  1014.                 
  1015.                 if LEAF_RANDVEC:    rand_vec = Vector( Rand(-1, 1), Rand(-1, 1), Rand(-1, 1) ).normalize() * LEAF_RANDVEC
  1016.                 else:                rand_vec = Vector( )
  1017.                 
  1018.                 return Matrix([scale,0,0],[0,scale,0],[0,0,scale]).resize4x4() * (self.no + rand_vec).toTrackQuat('x', 'z').toMatrix().resize4x4() * TranslationMatrix(self.tailCo)
  1019.             """
  1020.         def distripute_seg_on_mesh(me__, face_group):
  1021.             """
  1022.             add segment endpoints
  1023.             """
  1024.             
  1025.             vert_segment_mapping = {}
  1026.             for f in face_group:
  1027.                 for v in f:
  1028.                     i = v.index
  1029.                     if i not in vert_segment_mapping:
  1030.                         vert_segment_mapping[i] = len(segments_all)
  1031.                         v.sel = True
  1032.                         seg = segment(0)
  1033.                         # seg.tailCo = v.co.copy() # headCo undefined atm.
  1034.                         seg.tailCo = v.co.copy() * self_tree.objectTwigBoundsMat * self_tree.objectCurveIMat
  1035.                         
  1036.                         # self_tree.objectCurveMat
  1037.                         
  1038.                         seg.no = v.no
  1039.             
  1040.             # Build connectivity
  1041.             for ed in me__.edges:
  1042.                 if ed.v1.sel and ed.v2.sel:
  1043.                     i1,i2 = ed.key
  1044.                     i1 = vert_segment_mapping[i1]
  1045.                     i2 = vert_segment_mapping[i2]
  1046.                     
  1047.                     segments_all[i1].brothers.append( segments_all[i2] )
  1048.                     segments_all[i2].brothers.append( segments_all[i1] )
  1049.             
  1050.             # Dont need to return anything, added when created.
  1051.         
  1052.         def set_seg_attach_point(seg, interior_points, twig_fill_rand_scale):
  1053.             """
  1054.             Can only run on end nodes that have normals set
  1055.             """
  1056.             best_dist = 1000000000.0
  1057.             best_point = None
  1058.             
  1059.             co = seg.tailCo
  1060.             
  1061.             for pt in interior_points:
  1062.                 # line from the point to the seg endpoint
  1063.                 
  1064.                 line_normal = seg.tailCo - pt.nextMidCo
  1065.                 l = line_normal.length
  1066.                 
  1067.                 
  1068.                 cross1 = seg.no.cross(line_normal)
  1069.                 cross2 = pt.no.cross(line_normal)
  1070.                 
  1071.                 angle_line = min(AngleBetweenVecsSafe(cross1, cross2), AngleBetweenVecsSafe(cross1, -cross2))
  1072.                 angle_leaf_no_diff = min(AngleBetweenVecsSafe(line_normal, seg.no), AngleBetweenVecsSafe(line_normal, -seg.no))
  1073.                 
  1074.                 # BEST_ANG=66.0
  1075.                 # angle = 66.0 # min(AngleBetweenVecs(v2_co-v1_co, leaf.co-cc), AngleBetweenVecs(v1_co-v2_co, leaf.co-cc))
  1076.                 # print angle, angle2
  1077.                 # l = (l * ((1+abs(angle-BEST_ANG))**2 )) / (1+angle_line)
  1078.                 l = (1+(angle_leaf_no_diff/180)) * (1+(angle_line/180)) * l
  1079.                 
  1080.                 if l < best_dist:
  1081.                     best_pt = pt
  1082.                     best_co = pt.nextMidCo
  1083.                     
  1084.                     best_dist = l
  1085.     
  1086.             # twig_fill_rand_scale
  1087.             seg.headCo = best_co.copy()
  1088.             
  1089.             if twig_fill_rand_scale:
  1090.                 seg_dir = seg.tailCo - seg.headCo
  1091.                 
  1092.                 seg_dir.length = seg_dir.length * ( 1.0 - (next_random_num(rnd)*twig_fill_rand_scale) )
  1093.                 seg.tailCo = seg.headCo + seg_dir
  1094.             
  1095.             
  1096.             if best_pt.childCount < 4:
  1097.                 # Watch this!!! adding a user before its attached and the branch is created!
  1098.                 # make sure if its not added later on, this isnt left added
  1099.                 best_pt.childCount += 1
  1100.                 
  1101.                 # True/False denotes weather we try to connect to our parent branch
  1102.                 seg.bpt = (best_pt, True)
  1103.             else:
  1104.                 seg.bpt = (best_pt, False)
  1105.                 
  1106.             return True
  1107.  
  1108.  
  1109.         # END Twig code, next add them
  1110.         
  1111.         
  1112.         """
  1113.         Uses a reversed approch, fill in twigs from a bounding mesh
  1114.         """
  1115.         # print "twig_fill_fork_angle_max"
  1116.         # twig_fill_fork_angle_max = 60.0 # 
  1117.         # forward_diff_bezier will fill in the blanks
  1118.         # nice we can reuse these for every curve segment :)
  1119.         pointlist = [[None, None, None] for i in xrange(self_tree.steps+1)]
  1120.         radlist = [ None for i in xrange(self_tree.steps+1) ]
  1121.         
  1122.         orig_branch_count = len(self_tree.branches_all)
  1123.         
  1124.         for face_group in BPyMesh.mesh2linkedFaces(self_tree.objectTwigBoundsMesh):
  1125.             # Set the selection to do point inside.
  1126.             self_tree.objectTwigBoundsMesh.sel = False
  1127.             for f in face_group: f.sel = True
  1128.             
  1129.             interior_points = []
  1130.             interior_normal = Vector()
  1131.             for i, brch in enumerate(self_tree.branches_all):
  1132.                 
  1133.                 if i == orig_branch_count:
  1134.                     break # no need to check new branches are inside us
  1135.                     
  1136.                 for pt in brch.bpoints:
  1137.                     if pt.next and pt.childCount < 4: # cannot attach to the last points
  1138.                         if self_tree.isPointInTwigBounds(pt.co, True): # selected_only
  1139.                             interior_points.append(pt)
  1140.                             interior_normal += pt.no * pt.radius
  1141.             
  1142.             segments_all[:] = []
  1143.             segments_level[:] = []
  1144.             
  1145.             if interior_points:
  1146.                 # Ok, we can add twigs now
  1147.                 distripute_seg_on_mesh( self_tree.objectTwigBoundsMesh, face_group )
  1148.                 
  1149.                 for seg in segments_level[0]: # only be zero segments
  1150.                     # Warning, increments the child count for bpoints we attach to!!
  1151.                     set_seg_attach_point(seg, interior_points, twig_fill_rand_scale)
  1152.                 
  1153.                 # Try sorting by other properties! this is ok for now
  1154.                 for segments_level_current in segments_level:
  1155.                     try:    segments_level_current.sort( key = lambda seg:    -(seg.headCo-seg.tailCo).length )
  1156.                     except:    segments_level_current.sort( lambda a,b: cmp((b.headCo-b.tailCo).length, (a.headCo-a.tailCo).length) ) # py2.3
  1157.                 
  1158.                 for level in xrange(twig_fill_levels):
  1159.                     if len(segments_level) > level:
  1160.                         for seg in segments_level[level]:
  1161.                             # print level, seg.brothers
  1162.                             if seg.mergeCount == 0:
  1163.                                 seg_merge = seg.findBestMerge(twig_fill_fork_angle_max)
  1164.                                 if seg_merge:
  1165.                                     seg.merge( seg_merge )
  1166.                     
  1167.                     if len(segments_level) > level+1:
  1168.                         for seg in segments_level[level+1]:
  1169.                             seg.calcBrothers()
  1170.                 
  1171.                 for seg in segments_all:
  1172.                     if seg.parent == None:
  1173.                         seg.levelFromRoot = 0
  1174.                         seg.calcLevelFromRoot()
  1175.                 
  1176.                 '''
  1177.                 for i, seg in enumerate(segments_all):    
  1178.                     # Make a branch from this data!
  1179.                     
  1180.                     brch = branch()
  1181.                     brch.type = BRANCH_TYPE_FILL
  1182.                     self_tree.branches_all.append(brch)
  1183.                     
  1184.                     # ============================= do this per bez pair
  1185.                     # 1 is the base and 2 is the tail
  1186.                     
  1187.                     #p1_h1 = seg.getHeadHandle()
  1188.                     p1_co = seg.headCo.copy()
  1189.                     p1_h2 = seg.getHeadHandle() # isnt used
  1190.                     
  1191.                     p2_h1 = seg.getTailHandle()
  1192.                     p2_co = seg.tailCo.copy()
  1193.                     #p2_h2 = seg.getTailHandle() # isnt used
  1194.                     
  1195.                     
  1196.                     bez1_vec = (None, p1_co, p1_h2)
  1197.                     bez2_vec = (p2_h1, p2_co, None)
  1198.                     
  1199.                     seg_root = seg.getRootSeg()
  1200.                     
  1201.                     radius_root = seg_root.bpt.radius * twig_fill_radius_factor
  1202.                     # Clamp so the head is never smaller then the tail
  1203.                     if radius_root < twig_fill_radius_min: radius_root = twig_fill_radius_min
  1204.                         
  1205.                     if seg_root.levelFromLeaf:
  1206.                         # print seg_root.levelFromLeaf, seg.levelFromRoot
  1207.                         WIDTH_STEP = (radius_root - twig_fill_radius_min) / (seg_root.levelFromLeaf+1)
  1208.                         
  1209.                         radius1 = twig_fill_radius_min + (WIDTH_STEP * (seg.levelFromLeaf+1))
  1210.                         if seg.levelFromLeaf:    radius2 = twig_fill_radius_min + (WIDTH_STEP * seg.levelFromLeaf)
  1211.                         else:                    radius2 = twig_fill_radius_min
  1212.                     else:
  1213.                         radius1 = radius_root
  1214.                         radius2 = twig_fill_radius_min 
  1215.                     
  1216.                     
  1217.                     points_from_bezier_seg(self_tree.steps, pointlist, radlist, bez1_vec, bez2_vec, radius1, radius2)
  1218.                     
  1219.                     # dont apply self_tree.limbScale here! - its alredy done
  1220.                     bpoints = [ bpoint(brch, Vector(pointlist[ii]), Vector(), radlist[ii]) for ii in xrange(len(pointlist)) ]
  1221.                     
  1222.                     # remove endpoint for all but the last
  1223.                     #if i != len(bez_list)-1:
  1224.                     #    bpoints.pop()
  1225.                     
  1226.                     brch.bpoints.extend(bpoints)
  1227.                     # =============================
  1228.                     
  1229.                     # Finalize once point data is there
  1230.                     brch.calcData()
  1231.                 #
  1232.                 #preview_curve()
  1233.                 '''
  1234.             
  1235.                 for segments_level_current in reversed(segments_level):
  1236.                     for seg in segments_level_current:
  1237.                         if seg.used == False and (seg.parent == None or seg.parent.used == True):
  1238.                             
  1239.                             # The root segment for this set of links.
  1240.                             # seg_root_linked = seg
  1241.                             
  1242.                             brch = branch()
  1243.                             brch.type = BRANCH_TYPE_FILL
  1244.                             self_tree.branches_all.append(brch)
  1245.                             
  1246.                             # Can we attach to a real branch?
  1247.                             if seg.parent == None:
  1248.                                 if seg.bpt[1]: # we can do a real join into the attach point
  1249.                                     brch.parent_pt = seg.bpt[0]
  1250.                                     # brch.parent_pt.childCount # this has alredy changed from 
  1251.                             
  1252.                             '''
  1253.                             if seg.parent:
  1254.                                 if seg.bpt[1] == 2:
  1255.                                     #if seg.bpt[1]:
  1256.                                     # print "Making Connection"
  1257.                                     if seg.bpt[0] == None:
  1258.                                         raise "Error"
  1259.                                     if seg.bpt[1] != 2:
  1260.                                         print seg.bpt[1]
  1261.                                         raise "Error"
  1262.                                     
  1263.                                     brch.parent_pt = seg.bpt[1]
  1264.                                     brch.parent_pt.childCount += 1
  1265.                                     if brch.parent_pt.childCount > 4:
  1266.                                         raise "Aeeae"
  1267.                                     print "\n\nM<aking Joint!!"
  1268.                             '''
  1269.                             
  1270.                             if seg.parent:
  1271.                                 sibling = seg.sibling()
  1272.                                 if sibling.new_bpt:
  1273.                                     if sibling.new_bpt.childCount < 4:
  1274.                                         brch.parent_pt = sibling.new_bpt
  1275.                                         brch.parent_pt.childCount +=1
  1276.                             
  1277.                             # Go down the hierarhy
  1278.                             is_first = True
  1279.                             while seg != None:
  1280.                                 seg.used = True
  1281.                                 
  1282.                                 # ==============================================
  1283.                                 
  1284.                                 #p1_h1 = seg.getHeadHandle()
  1285.                                 p1_co = seg.headCo.copy()
  1286.                                 p1_h2 = seg.getHeadHandle() # isnt used
  1287.                                 
  1288.                                 p2_h1 = seg.getTailHandle()
  1289.                                 p2_co = seg.tailCo.copy()
  1290.                                 #p2_h2 = seg.getTailHandle() # isnt used
  1291.                                 
  1292.                                 
  1293.                                 bez1_vec = (None, p1_co, p1_h2)
  1294.                                 bez2_vec = (p2_h1, p2_co, None)
  1295.                                 
  1296.                                 seg_root = seg.getRootSeg()
  1297.                                 
  1298.                                 radius_root = seg_root.bpt[0].radius * twig_fill_radius_factor
  1299.                                 # Clamp so the head is never smaller then the tail
  1300.                                 if radius_root < twig_fill_radius_min: radius_root = twig_fill_radius_min
  1301.                                     
  1302.                                 if seg_root.levelFromLeaf:    
  1303.                                     # print seg_root.levelFromLeaf, seg.levelFromRoot
  1304.                                     widthStep = (radius_root - twig_fill_radius_min) / (seg_root.levelFromLeaf+1)
  1305.                                     
  1306.                                     radius1 = twig_fill_radius_min + (widthStep * (seg.levelFromLeaf+1))
  1307.                                     if seg.levelFromLeaf:    radius2 = twig_fill_radius_min + (widthStep * seg.levelFromLeaf)
  1308.                                     else:                    radius2 = twig_fill_radius_min
  1309.                                 else:
  1310.                                     radius1 = radius_root
  1311.                                     radius2 = twig_fill_radius_min 
  1312.                                 
  1313.                                 points_from_bezier_seg(self_tree.steps, pointlist, radlist, bez1_vec, bez2_vec, radius1, radius2)
  1314.                                 
  1315.                                 
  1316.                                 start_pointlist = 0
  1317.                                 
  1318.                                 # This is like baseTrim, (remove the base points to make nice joins, accounting for radius of parent point)
  1319.                                 # except we do it before the branch is made
  1320.                                 
  1321.                                 if brch.parent_pt:
  1322.                                     while len(pointlist) - start_pointlist > 2 and (Vector(pointlist[start_pointlist]) - brch.parent_pt.co).length < (brch.parent_pt.radius*2):
  1323.                                         start_pointlist +=1
  1324.  
  1325.                                 if is_first and brch.parent_pt:
  1326.                                     # We need to move the base point to a place where it looks good on the parent branch
  1327.                                     # to do this. move the first point, then remove the following points that look horrible (double back on themself)
  1328.                                     
  1329.                                     no = Vector(pointlist[0]) - Vector(pointlist[-1])
  1330.                                     no.length = brch.parent_pt.radius*2
  1331.                                     pointlist[0] = list(Vector(pointlist[0]) - no)
  1332.                                     
  1333.                                     """
  1334.                                     pointlist[1][0] = (pointlist[0][0] + pointlist[2][0])/2.0
  1335.                                     pointlist[1][1] = (pointlist[0][1] + pointlist[2][1])/2.0
  1336.                                     pointlist[1][2] = (pointlist[0][2] + pointlist[2][2])/2.0
  1337.                                     
  1338.                                     pointlist[2][0] = (pointlist[1][0] + pointlist[3][0])/2.0
  1339.                                     pointlist[2][1] = (pointlist[1][1] + pointlist[3][1])/2.0
  1340.                                     pointlist[2][2] = (pointlist[1][2] + pointlist[3][2])/2.0
  1341.                                     """
  1342.                                     
  1343.                                     
  1344.                                 # Done setting the start point
  1345.                                     
  1346.                                     
  1347.                                 len_pointlist = len(pointlist)
  1348.                                 if seg.children:
  1349.                                     len_pointlist -= 1
  1350.                                 
  1351.                                 # dont apply self_tree.limbScale here! - its alredy done
  1352.                                 bpoints = [ bpoint(brch, Vector(pointlist[ii]), Vector(), radlist[ii]) for ii in xrange(start_pointlist, len_pointlist) ]
  1353.                                 brch.bpoints.extend( bpoints )
  1354.                                 # ==============================================
  1355.                                 
  1356.                                 seg.new_bpt = bpoints[0]
  1357.                                 
  1358.                                 if seg.children:
  1359.                                     seg = seg.children[0]
  1360.                                 else:
  1361.                                     seg = None
  1362.                                 
  1363.                                 is_first = False
  1364.                                 
  1365.                             # done adding points
  1366.                             brch.calcData()
  1367.                             
  1368.                             
  1369.                             
  1370.         
  1371.     def buildTwigs(self, twig_ratio, twig_select_mode, twig_select_factor):
  1372.         
  1373.         ratio_int = int(len(self.branches_all) * twig_ratio)
  1374.         if ratio_int == 0:
  1375.             return
  1376.         
  1377.         # So we only mix branches of similar lengths
  1378.         branches_sorted = self.branches_all[:]
  1379.         
  1380.         # Get the branches based on our selection method!
  1381.         if twig_select_mode==0:
  1382.             try:    branches_sorted.sort( key = lambda brch: brch.getLength())
  1383.             except:    branches_sorted.sort( lambda a,b: cmp(a.getLength(),a.getLength()) ) # py2.3
  1384.         elif twig_select_mode==1:
  1385.             try:    branches_sorted.sort( key = lambda brch:-brch.getLength())
  1386.             except:    branches_sorted.sort( lambda a,b: cmp(b.getLength(), a.getLength()) ) # py2.3
  1387.         elif twig_select_mode==2:
  1388.             try:    branches_sorted.sort( key = lambda brch:brch.getStraightness())
  1389.             except:    branches_sorted.sort( lambda a,b: cmp(a.getStraightness(), b.getStraightness())) # py2.3
  1390.         elif twig_select_mode==3:
  1391.             try:    branches_sorted.sort( key = lambda brch:-brch.getStraightness())
  1392.             except:    branches_sorted.sort( lambda a,b: cmp(b.getStraightness(), a.getStraightness())) # py2.3
  1393.         
  1394.         factor_int = int(len(self.branches_all) * twig_select_factor)
  1395.         branches_sorted[factor_int:] = []  # remove the last part of the list
  1396.         
  1397.         try:    branches_sorted.sort( key = lambda brch: len(brch.bpoints))
  1398.         except:    branches_sorted.sort( lambda a,b: cmp(len(a.bpoints), len(b.bpoints)) ) # py2.3
  1399.         
  1400.         branches_new = []
  1401.         #for i in xrange(ratio_int):
  1402.         tot_twigs = 0
  1403.         
  1404.         step = 1
  1405.         while tot_twigs < ratio_int and step < len(branches_sorted):
  1406.             # Make branches from the existing
  1407.             for j in xrange(step, len(branches_sorted)):
  1408.                 brch = branches_sorted[j-step].mixToNew(branches_sorted[j], None)
  1409.                 branches_new.append( brch )
  1410.                 tot_twigs +=1
  1411.                 
  1412.                 if tot_twigs > ratio_int:
  1413.                     break
  1414.         
  1415.         ### print "TwigCount", len(branches_new), ratio_int
  1416.         
  1417.         self.branches_twigs = branches_new
  1418.     
  1419.     def toDebugDisplay(self):
  1420.         '''
  1421.         Should be able to call this at any time to see whats going on, dosnt work so nice ATM.
  1422.         '''
  1423.         sce = bpy.data.scenes.active
  1424.         
  1425.         for ob in self.debug_objects:
  1426.             for ob in sce.objects:
  1427.                 sce.objects.unlink(ob)
  1428.         
  1429.         for branch_index, brch in enumerate(self.branches_all):
  1430.             pt_index = 0
  1431.             for pt_index, pt in enumerate(brch.bpoints):
  1432.                 name = '%.3d_%.3d' % (branch_index, pt_index) 
  1433.                 if pt.next==None:
  1434.                     name += '_end'
  1435.                 if pt.prev==None:
  1436.                     name += '_start'
  1437.                     
  1438.                 ob = sce.objects.new('Empty', name)
  1439.                 self.debug_objects.append(ob)
  1440.                 mat = ScaleMatrix(pt.radius, 4) * TranslationMatrix(pt.co)
  1441.                 ob.setMatrix(mat)
  1442.                 ob.setDrawMode(8) # drawname
  1443.         Blender.Window.RedrawAll()
  1444.         
  1445.         
  1446.     
  1447.     def toMesh(self, mesh=None,\
  1448.             do_uv=True,\
  1449.             do_uv_keep_vproportion=True,\
  1450.             do_uv_vnormalize=False,\
  1451.             do_uv_uscale=False,\
  1452.             uv_image = None,\
  1453.             uv_x_scale=1.0,\
  1454.             uv_y_scale=4.0,\
  1455.             do_uv_blend_layer= False,\
  1456.             do_cap_ends=False,\
  1457.         ):
  1458.         
  1459.         self.mesh = freshMesh(mesh)
  1460.         totverts = 0
  1461.         
  1462.         for brch in self.branches_all:
  1463.             totverts += len(brch.bpoints)
  1464.         
  1465.         self.mesh.verts.extend( [ (0.0,0.0,0.0) ] * ((totverts * 4)+1) ) # +1 is a dummy vert
  1466.         verts = self.mesh.verts
  1467.         
  1468.         # Assign verts to points, 4 verts for each point.
  1469.         i = 1 # dummy vert, should be 0
  1470.         for brch in self.branches_all:            
  1471.             for pt in brch.bpoints:
  1472.                 pt.verts[0] = verts[i]
  1473.                 pt.verts[1] = verts[i+1]
  1474.                 pt.verts[2] = verts[i+2]
  1475.                 pt.verts[3] = verts[i+3]
  1476.                 i+=4
  1477.                 
  1478.             # Do this again because of collapsing
  1479.             # pt.calcVerts(brch)
  1480.         
  1481.         # roll the tube so quads best meet up to their branches.
  1482.         for brch in self.branches_all:
  1483.             #for pt in brch.bpoints:
  1484.             if brch.parent_pt:
  1485.                 
  1486.                 # Use temp lists for gathering an average
  1487.                 if brch.parent_pt.roll_angle == None:
  1488.                     brch.parent_pt.roll_angle = [brch.getParentQuadAngle()]
  1489.                 # More then 2 branches use this point, add to the list
  1490.                 else:
  1491.                     brch.parent_pt.roll_angle.append( brch.getParentQuadAngle() )
  1492.         
  1493.         # average the temp lists into floats
  1494.         for brch in self.branches_all:
  1495.             #for pt in brch.bpoints:
  1496.             if brch.parent_pt and type(brch.parent_pt.roll_angle) == list:
  1497.                 # print brch.parent_pt.roll_angle
  1498.                 f = 0.0
  1499.                 for val in brch.parent_pt.roll_angle:
  1500.                     f += val
  1501.                 brch.parent_pt.roll_angle = f/len(brch.parent_pt.roll_angle)
  1502.         
  1503.         # set the roll of all the first segments that have parents,
  1504.         # this is because their roll is set from their parent quad and we dont want them to roll away from that.
  1505.         for brch in self.branches_all:
  1506.             if brch.parent_pt:
  1507.                 # if the first joint has a child then apply half the roll
  1508.                 # theres no correct solition here, but this seems ok
  1509.                 if brch.bpoints[0].roll_angle != None:
  1510.                     #brch.bpoints[0].roll_angle *= 0.5
  1511.                     #brch.bpoints[0].roll_angle = 0.0
  1512.                     #brch.bpoints[1].roll_angle = 0.0
  1513.                     brch.bpoints[0].roll_angle = 0.0
  1514.                     pass
  1515.                 else:
  1516.                     # our roll was set from the branches parent and needs no changing
  1517.                     # set it to zero so the following functions know to interpolate.
  1518.                     brch.bpoints[0].roll_angle = 0.0
  1519.                     #brch.bpoints[1].roll_angle = 0.0
  1520.         
  1521.         '''
  1522.         Now interpolate the roll!
  1523.         The method used here is a little odd.
  1524.         
  1525.         * first loop up the branch and set each points value to the "last defined" value and record the steps
  1526.         since the last defined value
  1527.         * Do the same again but backwards
  1528.         
  1529.         now for each undefined value we have 1 or 2 values, if its 1 its simple we just use that value 
  1530.         ( no interpolation ), if there are 2 then we use the offsets from each end to work out the interpolation.
  1531.         
  1532.         one up, one back, and another to set the values, so 3 loops all up.
  1533.         '''
  1534.         #### print "scan up the branch..."
  1535.         for brch in self.branches_all:
  1536.             last_value = None
  1537.             last_index = -1
  1538.             for i in xrange(len(brch.bpoints)):
  1539.                 pt = brch.bpoints[i]
  1540.                 if type(pt.roll_angle) in (float, int):
  1541.                     last_value = pt.roll_angle
  1542.                     last_index = i
  1543.                 else:
  1544.                     if type(last_value) in (float, int):
  1545.                         # Assign a list, because there may be a connecting roll value from another joint
  1546.                         pt.roll_angle = [(last_value, i-last_index)]
  1547.                 
  1548.             #### print "scan down the branch..."
  1549.             last_value = None
  1550.             last_index = -1
  1551.             for i in xrange(len(brch.bpoints)-1, -1, -1): # same as above but reverse
  1552.                 pt = brch.bpoints[i]
  1553.                 if type(pt.roll_angle) in (float, int):
  1554.                     last_value = pt.roll_angle
  1555.                     last_index = i
  1556.                 else:
  1557.                     if last_value != None:
  1558.                         if type(pt.roll_angle) == list:
  1559.                             pt.roll_angle.append((last_value, last_index-i))
  1560.                         else:
  1561.                             #pt.roll_angle = [(last_value, last_index-i)]
  1562.                             
  1563.                             # Dont bother assigning a list because we wont need to add to it later
  1564.                             pt.roll_angle = last_value 
  1565.             
  1566.             # print "looping ,...."
  1567.             ### print "assigning/interpolating roll values"
  1568.             for pt in brch.bpoints:
  1569.                 
  1570.                 # print "this roll IS", pt.roll_angle
  1571.                 
  1572.                 if pt.roll_angle == None:
  1573.                     continue
  1574.                 elif type(pt.roll_angle) in (float, int):
  1575.                     pass
  1576.                 elif len(pt.roll_angle) == 1:
  1577.                     pt.roll_angle = pt.roll_angle[0][0]
  1578.                 else:
  1579.                     # interpolate
  1580.                     tot = pt.roll_angle[0][1] + pt.roll_angle[1][1]
  1581.                     pt.roll_angle = \
  1582.                      (pt.roll_angle[0][0] * (tot - pt.roll_angle[0][1]) +\
  1583.                       pt.roll_angle[1][0] * (tot - pt.roll_angle[1][1])) / tot
  1584.                     
  1585.                     #### print pt.roll_angle, 'interpolated roll'
  1586.                     
  1587.                 pt.roll(pt.roll_angle)
  1588.                 
  1589.         # Done with temp average list. now we know the best roll for each branch.
  1590.         
  1591.         # mesh the data
  1592.         for brch in self.branches_all:
  1593.             for pt in brch.bpoints:
  1594.                 pt.toMesh(self.mesh)
  1595.         
  1596.         #faces_extend = [ face for brch in self.branches_all for pt in brch.bpoints for face in pt.faces if face ]
  1597.         
  1598.         
  1599.         
  1600.         faces_extend = []
  1601.         for brch in self.branches_all:
  1602.             if brch.parent_pt:
  1603.                 faces_extend.extend(brch.faces)
  1604.             for pt in brch.bpoints:
  1605.                 for face in pt.faces:
  1606.                     if face:
  1607.                         faces_extend.append(face)
  1608.         
  1609.         if do_cap_ends:
  1610.             # TODO - UV map and image?
  1611.             faces_extend.extend([ brch.bpoints[-1].verts for brch in self.branches_all ])
  1612.         
  1613.         faces = self.mesh.faces
  1614.  
  1615.         faces.extend(faces_extend, smooth=True)
  1616.         
  1617.         if do_uv:
  1618.             # Assign the faces back
  1619.             face_index = 0
  1620.             for brch in self.branches_all:
  1621.                 if brch.parent_pt:
  1622.                     for i in (0,1,2,3):
  1623.                         face = brch.faces[i] = faces[face_index+i]
  1624.                     face_index +=4
  1625.                 
  1626.                 for pt in brch.bpoints:
  1627.                     for i in (0,1,2,3):
  1628.                         if pt.faces[i]:
  1629.                             pt.faces[i] = faces[face_index]
  1630.                             face_index +=1
  1631.             
  1632.             #if self.mesh.faces:
  1633.             #    self.mesh.faceUV = True
  1634.             mesh.addUVLayer( 'base' )
  1635.             
  1636.             # rename the uv layer
  1637.             #mesh.renameUVLayer(mesh.getUVLayerNames()[0], 'base')
  1638.             
  1639.             for brch in self.branches_all:
  1640.                 
  1641.                 uv_x_scale_branch = 1.0
  1642.                 if do_uv_uscale:
  1643.                     uv_x_scale_branch = 0.0
  1644.                     for pt in brch.bpoints:
  1645.                         uv_x_scale_branch += pt.radius
  1646.                     
  1647.                     uv_x_scale_branch = uv_x_scale_branch / len(brch.bpoints)
  1648.                     # uv_x_scale_branch = brch.bpoints[0].radius
  1649.                 
  1650.                 if do_uv_vnormalize:
  1651.                     uv_normalize = []
  1652.                 
  1653.                 def uvmap_faces(my_faces, y_val, y_size):
  1654.                     '''
  1655.                     Accept a branch or pt faces
  1656.                     '''
  1657.                     uv_ls = [None, None, None, None]
  1658.                     for i in (0,1,2,3):
  1659.                         if my_faces[i]:
  1660.                             if uv_image:
  1661.                                 my_faces[i].image = uv_image
  1662.                             uvs = my_faces[i].uv
  1663.                         else:
  1664.                             # Use these for calculating blending values
  1665.                             uvs = [Vector(0,0), Vector(0,0), Vector(0,0), Vector(0,0)]
  1666.                         
  1667.                         uv_ls[i] = uvs
  1668.                         
  1669.                         x1 = i*0.25 * uv_x_scale * uv_x_scale_branch    
  1670.                         x2 = (i+1)*0.25 * uv_x_scale * uv_x_scale_branch
  1671.                         
  1672.                         uvs[3].x = x1;
  1673.                         uvs[3].y = y_val+y_size
  1674.                         
  1675.                         uvs[0].x = x1
  1676.                         uvs[0].y = y_val
  1677.                         
  1678.                         uvs[1].x = x2
  1679.                         uvs[1].y = y_val
  1680.                         
  1681.                         uvs[2].x = x2
  1682.                         uvs[2].y = y_val+y_size
  1683.                         
  1684.                         if do_uv_vnormalize:
  1685.                             uv_normalize.extend(uvs)
  1686.                     
  1687.                     return uv_ls
  1688.                     
  1689.                 # Done uvmap_faces
  1690.                 
  1691.                 y_val = 0.0
  1692.                 
  1693.                 if brch.parent_pt:
  1694.                     y_size = (brch.getParentFaceCent() - brch.bpoints[0].co).length
  1695.                     
  1696.                     if do_uv_keep_vproportion:
  1697.                         y_size = y_size / ((brch.bpoints[0].radius + brch.parent_pt.radius)/2) * uv_y_scale
  1698.                     
  1699.                     brch.uv = uvmap_faces(brch.faces, 0.0, y_size)
  1700.                     
  1701.                     y_val += y_size
  1702.                 
  1703.                 for pt in brch.bpoints:
  1704.                     if pt.next:
  1705.                         y_size = (pt.co-pt.next.co).length
  1706.                         # scale the uvs by the radius, avoids stritching.
  1707.                         if do_uv_keep_vproportion:
  1708.                             y_size = y_size / pt.radius * uv_y_scale
  1709.                         pt.uv = uvmap_faces(pt.faces, y_val, y_size)
  1710.                         y_val += y_size
  1711.                 
  1712.                 
  1713.                 if do_uv_vnormalize and uv_normalize:
  1714.                     # Use yscale here so you can choose to have half the normalized value say.
  1715.                     vscale = (1/uv_normalize[-1].y) * uv_y_scale
  1716.                     for uv in uv_normalize:
  1717.                         uv.y *= vscale
  1718.             
  1719.             
  1720.             # Done with UV mapping the first layer! now map the blend layers
  1721.             if do_uv_blend_layer:
  1722.                 # Set up the blend UV layer - this is simply the blending for branch joints
  1723.                 mesh.addUVLayer( 'blend' )
  1724.                 mesh.activeUVLayer = 'blend'
  1725.                 
  1726.                 # Set all faces to be on full blend
  1727.                 for f in mesh.faces:
  1728.                     for uv in f.uv:
  1729.                         uv.y = uv.x = 0.0
  1730.                 
  1731.                 for brch in self.branches_all:
  1732.                     if brch.parent_pt:
  1733.                         for f in brch.faces:
  1734.                             if f:
  1735.                                 uvs = f.uv
  1736.                                 uvs[0].x = uvs[1].x = uvs[2].x = uvs[3].x = 0.0 
  1737.                                 uvs[0].y = uvs[1].y = 1.0 # swap these? - same as inverting the blend
  1738.                                 uvs[2].y = uvs[3].y = 0.0
  1739.                 
  1740.                 # Set up the join UV layer, this overlays nice blended
  1741.                 mesh.addUVLayer( 'join' )
  1742.                 mesh.activeUVLayer = 'join'
  1743.                 
  1744.                 # Set all faces to be on full blend
  1745.                 for f in mesh.faces:
  1746.                     for uv in f.uv:
  1747.                         uv.y = uv.x = 0.0
  1748.                 
  1749.                 for brch in self.branches_all:
  1750.                     if brch.parent_pt:
  1751.                         # The UV's that this branch would cover if it was a face, 
  1752.                         uvs_base = brch.parent_pt.uv[brch.getParentQuadIndex()]
  1753.                         
  1754.                         uvs_base_mid = Vector(0,0)
  1755.                         for uv in uvs_base:
  1756.                             uvs_base_mid += uv
  1757.                             
  1758.                         uvs_base_mid *= 0.25
  1759.                         
  1760.                         # TODO - Factor scale and distance in here 
  1761.                         ## uvs_base_small = [(uv+uvs_base_mid)*0.5 for uv in uvs_base]
  1762.                         uvs_base_small = [uvs_base_mid, uvs_base_mid, uvs_base_mid, uvs_base_mid]
  1763.                         
  1764.                         if brch.faces[0]:
  1765.                             f = brch.faces[0]
  1766.                             uvs = f.uv
  1767.                             uvs[0][:] = uvs_base[0]
  1768.                             uvs[1][:] = uvs_base[1]
  1769.                             
  1770.                             uvs[2][:] = uvs_base_small[1]
  1771.                             uvs[3][:] = uvs_base_small[0]
  1772.                         
  1773.                         if brch.faces[1]:
  1774.                             f = brch.faces[1]
  1775.                             uvs = f.uv
  1776.                             uvs[0][:] = uvs_base[1]
  1777.                             uvs[1][:] = uvs_base[2]
  1778.                             
  1779.                             uvs[2][:] = uvs_base_small[2]
  1780.                             uvs[3][:] = uvs_base_small[1]
  1781.                             
  1782.                         if brch.faces[2]:
  1783.                             f = brch.faces[2]
  1784.                             uvs = f.uv
  1785.                             uvs[0][:] = uvs_base[2]
  1786.                             uvs[1][:] = uvs_base[3]
  1787.                             
  1788.                             uvs[2][:] = uvs_base_small[3]
  1789.                             uvs[3][:] = uvs_base_small[2]
  1790.                             
  1791.                         if brch.faces[3]:
  1792.                             f = brch.faces[3]
  1793.                             uvs = f.uv
  1794.                             uvs[0][:] = uvs_base[3]
  1795.                             uvs[1][:] = uvs_base[0]
  1796.                             
  1797.                             uvs[2][:] = uvs_base_small[0]
  1798.                             uvs[3][:] = uvs_base_small[3]
  1799.             
  1800.             mesh.activeUVLayer = 'base'  # just so people dont get worried the texture is not there - dosnt effect rendering.
  1801.         else:
  1802.             # no UV's
  1803.             pass
  1804.         
  1805.         if do_cap_ends:
  1806.             # de-select end points for 
  1807.             i = len(faces)-1
  1808.             
  1809.             cap_end_face_start = len(faces) - len(self.branches_all)
  1810.             
  1811.             j = 0
  1812.             for i in xrange(cap_end_face_start, len(faces)):
  1813.                 self.branches_all[j].face_cap = faces[i]
  1814.                 faces[i].sel = 0
  1815.                 
  1816.                 # default UV's are ok for now :/
  1817.                 if do_uv and uv_image:
  1818.                     faces[i].image = uv_image
  1819.                 
  1820.                 j +=1
  1821.             
  1822.             # set edge crease for capped ends.
  1823.             for ed in self.mesh.edges:
  1824.                 if ed.v1.sel==False and ed.v2.sel==False:
  1825.                     ed.crease = 255
  1826.                     ed.sel = True # so its all selected still
  1827.             
  1828.         del faces_extend
  1829.         
  1830.         return self.mesh
  1831.     
  1832.     def toLeafMesh(self, mesh_leaf,\
  1833.             leaf_branch_limit = 0.5,\
  1834.             leaf_branch_limit_rand = 0.8,\
  1835.             leaf_branch_limit_type_curve = False,\
  1836.             leaf_branch_limit_type_grow = False,\
  1837.             leaf_branch_limit_type_fill = False,\
  1838.             leaf_size = 0.5,\
  1839.             leaf_size_rand = 0.5,\
  1840.             leaf_branch_density = 0.2,\
  1841.             leaf_branch_pitch_angle = 0.0,\
  1842.             leaf_branch_pitch_rand = 0.2,\
  1843.             leaf_branch_roll_rand = 0.2,\
  1844.             leaf_branch_angle = 75.0,\
  1845.             leaf_rand_seed = 1.0,\
  1846.             leaf_object=None,\
  1847.         ):
  1848.         
  1849.         '''
  1850.         return a mesh with leaves seperate from the tree
  1851.         
  1852.         Add to the existing mesh.
  1853.         '''
  1854.         
  1855.         #radius = [(pt.radius for pt in self.branches_all for pt in brch.bpoints for pt in brch.bpoints]
  1856.         mesh_leaf = freshMesh(mesh_leaf)
  1857.         self.mesh_leaf = mesh_leaf
  1858.         
  1859.         # if not leaf_object: return # make the dupli anyway :/ - they can do it later or the script could complain
  1860.         
  1861.         if leaf_branch_limit == 1.0:
  1862.             max_radius = 1000000.0
  1863.         else:
  1864.             # We wont place leaves on all branches so...
  1865.             # first collect stats, we want to know the average radius and total segments
  1866.             totpoints = 0
  1867.             radius = 0.0
  1868.             max_radius = 0.0
  1869.             for brch in self.branches_all:
  1870.                 for pt in brch.bpoints:
  1871.                     radius += pt.radius
  1872.                     if pt.radius > max_radius:
  1873.                         max_radius = pt.radius
  1874.                 
  1875.                 #totpoints += len(brch.bpoints)
  1876.                 
  1877.             radius_max = max_radius * leaf_branch_limit
  1878.         
  1879.         verts_extend = []
  1880.         faces_extend = []
  1881.         
  1882.         co1 = Vector(0.0, -0.5, -0.5)
  1883.         co2 = Vector(0.0, -0.5, 0.5)
  1884.         co3 = Vector(0.0, 0.5, 0.5)
  1885.         co4 = Vector(0.0, 0.5, -0.5)
  1886.         
  1887.         rnd_seed = [leaf_rand_seed] # could have seed as an input setting
  1888.         
  1889.         for brch in self.branches_all:
  1890.             
  1891.             # quick test, do we need leaves on this branch?
  1892.             if leaf_branch_limit != 1.0 and brch.bpoints[-1].radius > radius_max:
  1893.                 continue
  1894.             
  1895.             
  1896.             for pt in brch.bpoints:
  1897.                 
  1898.                 # For each point we can add 2 leaves
  1899.                 for odd_even in (0,1):
  1900.                     
  1901.                     
  1902.                     if    (pt == brch.bpoints[-1] and odd_even==1) or \
  1903.                         (leaf_branch_density != 1.0 and leaf_branch_density < next_random_num(rnd_seed)):
  1904.                         pass
  1905.                     else:
  1906.                         if leaf_branch_limit_rand:
  1907.                             # (-1 : +1) * leaf_branch_limit_rand
  1908.                             rnd = 1 + (((next_random_num(rnd_seed) - 0.5) * 2 ) * leaf_branch_limit_rand)
  1909.                         else:
  1910.                             rnd = 1.0
  1911.                         
  1912.                         if pt.childCount == 0 and (leaf_branch_limit == 1.0 or (pt.radius * rnd) < radius_max):
  1913.                             leaf_size_tmp = leaf_size * (1.0-(next_random_num(rnd_seed)*leaf_size_rand))
  1914.                             
  1915.                             # endpoints dont rotate
  1916.                             if pt.next != None:
  1917.                                 cross1 = zup.cross(pt.no) # use this to offset the leaf later
  1918.                                 cross2 = cross1.cross(pt.no)
  1919.                                 if odd_even ==0:
  1920.                                     mat_yaw = RotationMatrix(leaf_branch_angle, 3, 'r',  cross2)
  1921.                                 else:
  1922.                                     mat_yaw = RotationMatrix(-leaf_branch_angle, 3, 'r', cross2)
  1923.                                 
  1924.                                 leaf_no = (pt.no * mat_yaw)
  1925.                                 
  1926.                                 # Correct upwards pointing from changing the yaw 
  1927.                                 #my_up = zup * mat
  1928.                                 
  1929.                                 # correct leaf location for branch width
  1930.                                 cross1.length = pt.radius/2
  1931.                                 leaf_co = pt.co + cross1
  1932.                             else:
  1933.                                 # no correction needed, we are at the end of the branch
  1934.                                 leaf_no = pt.no
  1935.                                 leaf_co = pt.co
  1936.                             
  1937.                             mat = Matrix([leaf_size_tmp,0,0],[0,leaf_size_tmp,0],[0,0,leaf_size_tmp]) * leaf_no.toTrackQuat('x', 'z').toMatrix()
  1938.                             
  1939.                             # Randomize pitch and roll for the leaf
  1940.                             
  1941.                             # work out the axis to pitch and roll
  1942.                             cross1 = zup.cross(leaf_no) # use this to offset the leaf later
  1943.                             if leaf_branch_pitch_rand or leaf_branch_pitch_angle:
  1944.                                 
  1945.                                 angle = -leaf_branch_pitch_angle
  1946.                                 if leaf_branch_pitch_rand:
  1947.                                     angle += leaf_branch_pitch_rand * ((next_random_num(rnd_seed)-0.5)*360)
  1948.                                 
  1949.                                 mat_pitch = RotationMatrix( angle, 3, 'r', cross1)
  1950.                                 mat = mat * mat_pitch
  1951.                             if leaf_branch_roll_rand:
  1952.                                 mat_roll =  RotationMatrix( leaf_branch_roll_rand * ((next_random_num(rnd_seed)-0.5)*360), 3, 'r', leaf_no)
  1953.                                 mat = mat * mat_roll
  1954.                             
  1955.                             mat = mat.resize4x4() * TranslationMatrix(leaf_co)
  1956.                             
  1957.                             i = len(verts_extend)
  1958.                             faces_extend.append( (i,i+1,i+2,i+3) )
  1959.                             verts_extend.extend([tuple(co4*mat), tuple(co3*mat), tuple(co2*mat), tuple(co1*mat)])
  1960.                     #count += 1
  1961.                 
  1962.         
  1963.         # setup dupli's
  1964.         
  1965.         self.mesh_leaf.verts.extend(verts_extend)
  1966.         self.mesh_leaf.faces.extend(faces_extend)
  1967.         
  1968.         return self.mesh_leaf
  1969.     
  1970.     
  1971.     def toArmature(self, ob_arm, armature):
  1972.         
  1973.         armature.drawType = Blender.Armature.STICK
  1974.         armature.makeEditable() # enter editmode
  1975.         
  1976.         # Assume toMesh has run
  1977.         self.armature = armature
  1978.         for bonename in armature.bones.keys():
  1979.             del armature.bones[bonename]
  1980.         
  1981.         
  1982.         group_names = []
  1983.         
  1984.         for i, brch in enumerate(self.branches_all):
  1985.             
  1986.             # get a list of parent points to make into bones. use parents and endpoints
  1987.             bpoints_parent = [pt for pt in brch.bpoints if pt.childCount or pt.prev == None or pt.next == None]
  1988.             bpbone_last = None
  1989.             for j in xrange(len(bpoints_parent)-1):
  1990.                 
  1991.                 # bone container class
  1992.                 bpoints_parent[j].bpbone = bpbone = bpoint_bone()
  1993.                 bpbone.name = '%i_%i' % (i,j) # must be unique
  1994.                 group_names.append(bpbone.name)
  1995.                 
  1996.                 bpbone.editbone = Blender.Armature.Editbone() # automatically added to the armature
  1997.                 self.armature.bones[bpbone.name] = bpbone.editbone
  1998.                 
  1999.                 bpbone.editbone.head = bpoints_parent[j].co
  2000.                 bpbone.editbone.head = bpoints_parent[j].co
  2001.                 bpbone.editbone.tail = bpoints_parent[j+1].co
  2002.                 
  2003.                 # parent the chain.
  2004.                 if bpbone_last:
  2005.                     bpbone.editbone.parent = bpbone_last.editbone
  2006.                     bpbone.editbone.options = [Blender.Armature.CONNECTED]
  2007.                 
  2008.                 bpbone_last = bpbone
  2009.         
  2010.         for brch in self.branches_all:
  2011.             if brch.parent_pt: # We must have a parent
  2012.                 
  2013.                 # find the bone in the parent chain to use for the parent of this
  2014.                 parent_pt = brch.parent_pt
  2015.                 bpbone_parent = None
  2016.                 while parent_pt:
  2017.                     bpbone_parent = parent_pt.bpbone
  2018.                     if bpbone_parent:
  2019.                         break
  2020.                     
  2021.                     parent_pt = parent_pt.prev
  2022.                 
  2023.                 
  2024.                 if bpbone_parent:
  2025.                     brch.bpoints[0].bpbone.editbone.parent = bpbone_parent.editbone
  2026.                 else: # in rare cases this may not work. should be verry rare but check anyway.
  2027.                     print 'this is really odd... look into the bug.'
  2028.         
  2029.         self.armature.update() # exit editmode
  2030.         
  2031.         # Skin the mesh
  2032.         if self.mesh:
  2033.             for group in group_names:
  2034.                 self.mesh.addVertGroup(group)
  2035.         
  2036.         for brch in self.branches_all:
  2037.             vertList = []
  2038.             group = '' # dummy
  2039.             
  2040.             for pt in brch.bpoints:
  2041.                 if pt.bpbone:
  2042.                     if vertList:
  2043.                         self.mesh.assignVertsToGroup(group, vertList, 1.0, Blender.Mesh.AssignModes.ADD)
  2044.                     
  2045.                     vertList = []
  2046.                     group = pt.bpbone.name
  2047.                 
  2048.                 vertList.extend( [v.index for v in pt.verts] )
  2049.             
  2050.             if vertList:
  2051.                 self.mesh.assignVertsToGroup(group, vertList, 1.0, Blender.Mesh.AssignModes.ADD)
  2052.         
  2053.         return self.armature
  2054.     
  2055.     def toAction(self, ob_arm, texture, anim_speed=1.0, anim_magnitude=1.0, anim_speed_size_scale=True, anim_offset_scale=1.0):
  2056.         # Assume armature
  2057.         action = ob_arm.action
  2058.         if not action:
  2059.             action = bpy.data.actions.new()
  2060.             action.fakeUser = False # so we dont get masses of bad data
  2061.             ob_arm.action = action
  2062.         
  2063.         # Blender.Armature.NLA.ob_arm.
  2064.         pose = ob_arm.getPose()
  2065.         
  2066.         for pose_bone in pose.bones.values():
  2067.             pose_bone.insertKey(ob_arm, 0, [Blender.Object.Pose.ROT], True)
  2068.         
  2069.         # Now get all the IPO's
  2070.         
  2071.         ipo_dict = action.getAllChannelIpos()
  2072.         # print ipo_dict
  2073.         
  2074.         # Sicne its per frame, it increases very fast. scale it down a bit
  2075.         anim_speed = anim_speed/100
  2076.         
  2077.         # When we have the same trees next to eachother, they will animate the same way unless we give each its own texture or offset settings.
  2078.         # We can use the object's location as a factor - this also will have the advantage? of seeing the animation move across the tree's
  2079.         # allow a scale so the difference between tree textures can be adjusted.
  2080.         anim_offset = self.objectCurve.matrixWorld.translationPart() * anim_offset_scale
  2081.         
  2082.         anim_speed_final = anim_speed
  2083.         # Assign drivers to them all
  2084.         for name, ipo in ipo_dict.iteritems():
  2085.             tex_str = 'b.Texture.Get("%s")' % texture.name
  2086.             
  2087.             if anim_speed_size_scale:
  2088.                 # Adjust the speed by the bone size.
  2089.                 # get the point from the name. a bit ugly but works fine ;) - Just dont mess the index up!
  2090.                 lookup = [int(val) for val in name.split('_')]
  2091.                 pt = self.branches_all[ lookup[0] ].bpoints[ lookup[1] ]
  2092.                 anim_speed_final = anim_speed / (1+pt.radius)
  2093.             
  2094.             cu = ipo[Blender.Ipo.PO_QUATX]
  2095.             try:    cu.delBezier(0) 
  2096.             except:    pass
  2097.             cu.driver = 2 # Python expression
  2098.             cu.driverExpression = '%.3f*(%s.evaluate(((b.Get("curframe")*%.3f)+%.3f,%.3f,%.3f)).w-0.5)' % (anim_magnitude, tex_str, anim_speed_final, anim_offset.x, anim_offset.y, anim_offset.z)
  2099.             
  2100.             cu = ipo[Blender.Ipo.PO_QUATY]
  2101.             try:    cu.delBezier(0) 
  2102.             except:    pass
  2103.             cu.driver = 2 # Python expression
  2104.             cu.driverExpression = '%.3f*(%s.evaluate((%.3f,(b.Get("curframe")*%.3f)+%.3f,%.3f)).w-0.5)' % (anim_magnitude, tex_str,  anim_offset.x, anim_speed_final, anim_offset.y, anim_offset.z)
  2105.             
  2106.             cu = ipo[Blender.Ipo.PO_QUATZ]
  2107.             try:    cu.delBezier(0) 
  2108.             except:    pass
  2109.             cu.driver = 2 # Python expression
  2110.             cu.driverExpression = '%.3f*(%s.evaluate((%.3f,%.3f,(b.Get("curframe")*%.3f)+%.3f)).w-0.5)' % (anim_magnitude, tex_str,  anim_offset.x, anim_offset.y, anim_speed_final, anim_offset.z)
  2111.         
  2112. xyzup = Vector(1,1,1).normalize()
  2113. xup = Vector(1,0,0)
  2114. yup = Vector(0,1,0)
  2115. zup = Vector(0,0,1)
  2116.  
  2117. class bpoint_bone:
  2118.     def __init__(self):
  2119.         self.name = None
  2120.         self.editbone = None
  2121.         self.blenbone = None
  2122.         self.posebone = None
  2123.  
  2124. class bpoint(object):
  2125.     ''' The point in the middle of the branch, not the mesh points
  2126.     '''
  2127.     __slots__ = 'branch', 'co', 'no', 'radius', 'vecs', 'verts', 'children', 'faces', 'uv', 'next', 'prev', 'childCount', 'bpbone', 'roll_angle', 'nextMidCo', 'childrenMidCo', 'childrenMidRadius', 'targetCos', 'inTwigBounds'
  2128.     def __init__(self, brch, co, no, radius):
  2129.         self.branch = brch
  2130.         self.co = co
  2131.         self.no = no
  2132.         self.radius = radius
  2133.         self.vecs =        [None, None, None, None] # 4 for now
  2134.         self.verts =    [None, None, None, None]
  2135.         self.children = [None, None, None, None] # child branches, dont fill in faces here
  2136.         self.faces = [None, None, None, None]
  2137.         self.uv = None # matching faces, except - UV's are calculated even if there is no face, this is so we can calculate the blending UV's
  2138.         self.next = None
  2139.         self.prev = None
  2140.         self.childCount = 0
  2141.         self.bpbone = None # bpoint_bone instance
  2142.         
  2143.         # when set, This is the angle we need to roll to best face our branches
  2144.         # the roll that is set may be interpolated if we are between 2 branches that need to roll.
  2145.         # Set to None means that the roll will be left default (from parent)
  2146.         self.roll_angle = None
  2147.         
  2148.         
  2149.         # The location between this and the next point,
  2150.         # if we want to be tricky we can try make this not just a simple
  2151.         # inbetween and use the normals to have some curvature
  2152.         self.nextMidCo = None
  2153.         
  2154.         # Similar to above, median point of all children
  2155.         self.childrenMidCo = None
  2156.         
  2157.         # Similar as above, but for radius
  2158.         self.childrenMidRadius = None
  2159.         
  2160.         # Target locations are used when you want to move the point to a new location but there are
  2161.         # more then 1 influence, build up a list and then apply
  2162.         self.targetCos = []
  2163.         
  2164.         # When we use twig bounding mesh, store if this point is in the bounding mesh. Assume true unless we set to false and do the test
  2165.         self.inTwigBounds = True 
  2166.     
  2167.     def __repr__(self):
  2168.         s = ''
  2169.         s += '\t\tco:', self.co
  2170.         s += '\t\tno:', self.no
  2171.         s += '\t\tradius:', self.radius
  2172.         s += '\t\tchildren:', [(child != False) for child in self.children]
  2173.         return s
  2174.         
  2175.     def makeLast(self):
  2176.         self.next = None
  2177.         self.nextMidCo = None
  2178.         self.childrenMidCo = None
  2179.     
  2180.     def setCo(self, co):
  2181.         self.co[:] = co
  2182.         self.calcNextMidCo()
  2183.         self.calcNormal()
  2184.         
  2185.         if self.prev:
  2186.             self.prev.calcNextMidCo()
  2187.             self.prev.calcNormal()
  2188.             self.prev.calcChildrenMidData()
  2189.         
  2190.         if self.next:
  2191.             self.prev.calcNormal()
  2192.         
  2193.         self.calcChildrenMidData()
  2194.         
  2195.         
  2196.     def nextLength(self):
  2197.         return (self.co-self.next.co).length
  2198.     def prevLength(self):
  2199.         return (self.co-self.prev.co).length
  2200.         
  2201.     def hasOverlapError(self):
  2202.         if self.prev == None:
  2203.             return False
  2204.         if self.next == None:
  2205.             return False
  2206.         '''
  2207.         # see if this point sits on the line between its siblings.
  2208.         co, fac = ClosestPointOnLine(self.co, self.prev.co, self.next.co)
  2209.         
  2210.         if fac >= 0.0 and fac <= 1.0:
  2211.             return False # no overlap, we are good
  2212.         else:
  2213.             return True # error, some overlap
  2214.         '''
  2215.         
  2216.         
  2217.         # Alternate method, maybe better
  2218.         ln = self.nextLength()
  2219.         lp = self.prevLength()
  2220.         ls = (self.prev.co-self.next.co).length
  2221.         
  2222.         # Are we overlapping? the length from our next or prev is longer then the next-TO-previous?
  2223.         if ln>ls or lp>ls:
  2224.             return True
  2225.         else:
  2226.             return False
  2227.         
  2228.     
  2229.     def applyTargetLocation(self):
  2230.         if not self.targetCos:
  2231.             return False
  2232.         elif len(self.targetCos) == 1:
  2233.             co_all = self.targetCos[0]
  2234.         else:
  2235.             co_all = Vector()
  2236.             for co in self.targetCos:
  2237.                 co_all += co
  2238.             co_all = co_all / len(self.targetCos)
  2239.         
  2240.         self.targetCos[:] = []
  2241.         
  2242.         length = (self.co-co_all).length
  2243.         # work out if we are moving up or down
  2244.         if AngleBetweenVecsSafe(self.no, self.co - co_all) < 90:
  2245.             
  2246.             # Up
  2247.             while length > (self.co-self.prev.co).length:
  2248.                 if not self.collapseUp():
  2249.                     break
  2250.             
  2251.         else:
  2252.             # Down
  2253.             while length*2 > (self.co-self.next.co).length:
  2254.                 if not self.collapseDown():
  2255.                     break
  2256.                 
  2257.         self.setCo(co_all)
  2258.         
  2259.         return True
  2260.     
  2261.     def calcNextMidCo(self):
  2262.         if not self.next:
  2263.             return None
  2264.         
  2265.         # be tricky later.
  2266.         self.nextMidCo = (self.co + self.next.co) * 0.5
  2267.     
  2268.     def calcNormal(self):
  2269.         if self.prev == None:
  2270.             self.no = (self.next.co - self.co).normalize()
  2271.         elif self.next == None:
  2272.             self.no = (self.co - self.prev.co).normalize()
  2273.         else:
  2274.             self.no = (self.next.co - self.prev.co).normalize()
  2275.     
  2276.     def calcChildrenMidData(self):
  2277.         '''
  2278.         Calculate childrenMidCo & childrenMidRadius
  2279.         This is a bit tricky, we need to find a point between this and the next,
  2280.         the medium of all children, this point will be on the line between this and the next.
  2281.         '''
  2282.         if not self.next:
  2283.             return None
  2284.         
  2285.         # factor between this and the next point
  2286.         radius = factor = factor_i = 0.0
  2287.         
  2288.         count = 0
  2289.         for brch in self.children:
  2290.             if brch: # we dont need the co at teh moment.
  2291.                 co, fac = ClosestPointOnLine(brch.bpoints[0].co, self.co, self.next.co)
  2292.                 factor_i += fac
  2293.                 count += 1
  2294.                 
  2295.                 radius += brch.bpoints[0].radius
  2296.         
  2297.         if not count:
  2298.             return
  2299.         
  2300.         # interpolate points 
  2301.         factor_i    = factor_i/count
  2302.         factor        = 1-factor_i
  2303.         
  2304.         self.childrenMidCo = (self.co * factor) + (self.next.co * factor_i)
  2305.         self.childrenMidRadius = radius
  2306.         
  2307.         #debug_pt(self.childrenMidCo)
  2308.         
  2309.     def getAbsVec(self, index):
  2310.         # print self.vecs, index
  2311.         return self.co + self.vecs[index]
  2312.     
  2313.     def slide(self, factor):
  2314.         '''
  2315.         Slides the segment up and down using the prev and next points
  2316.         '''
  2317.         self.setCo(self.slideCo(factor))
  2318.     
  2319.     def slideCo(self, factor):
  2320.         if self.prev == None or self.next == None or factor==0.0:
  2321.             return
  2322.         
  2323.         if factor < 0.0:
  2324.             prev_co = self.prev.co
  2325.             co = self.co
  2326.             
  2327.             ofs = co-prev_co
  2328.             ofs.length = abs(factor)
  2329.             self.co - ofs
  2330.             
  2331.             return self.co - ofs
  2332.         else:
  2333.             next_co = self.next.co
  2334.             co = self.co
  2335.             
  2336.             ofs = co-next_co
  2337.             ofs.length = abs(factor)
  2338.             
  2339.             return self.co - ofs
  2340.         
  2341.     
  2342.     def collapseDown(self):
  2343.         '''
  2344.         Collapse the next point into this one
  2345.         '''
  2346.         
  2347.         # self.next.next == None check is so we dont shorten the final length of branches.
  2348.         if self.next == None or self.next.next == None or self.childCount or self.next.childCount:
  2349.             return False
  2350.         
  2351.         self.branch.bpoints.remove(self.next)
  2352.         self.next = self.next.next # skip 
  2353.         self.next.prev = self
  2354.         
  2355.         # Watch this place - must update all data thats needed. roll is not calculaetd yet.
  2356.         self.calcNextMidCo()
  2357.         return True
  2358.         
  2359.     def collapseUp(self):
  2360.         '''
  2361.         Collapse the previous point into this one
  2362.         '''
  2363.         
  2364.         # self.next.next == None check is so we dont shorten the final length of branches.
  2365.         if self.prev == None or self.prev.prev == None or self.prev.childCount or self.prev.prev.childCount:
  2366.             return False
  2367.         
  2368.         self.branch.bpoints.remove(self.prev)
  2369.         self.prev = self.prev.prev # skip 
  2370.         self.prev.next = self
  2371.         
  2372.         # Watch this place - must update all data thats needed. roll is not calculaetd yet.
  2373.         self.prev.calcNextMidCo()
  2374.         return True
  2375.         
  2376.     
  2377.     def smooth(self, factor, factor_joint):
  2378.         '''
  2379.         Blend this point into the other 2 points
  2380.         '''
  2381.         if self.next == None or self.prev == None:
  2382.             return False
  2383.         
  2384.         if self.childCount or self.prev.childCount:
  2385.             factor = factor_joint;
  2386.         
  2387.         if factor==0.0:
  2388.             return False;
  2389.         
  2390.         radius = (self.next.radius + self.prev.radius)/2.0
  2391.         no = (self.next.no + self.prev.no).normalize()
  2392.         
  2393.         # do a line intersect to work out the best location
  2394.         '''
  2395.         cos = LineIntersect(    self.next.co, self.next.co+self.next.no,\
  2396.                                 self.prev.co, self.prev.co+self.prev.no)
  2397.         if cos == None:
  2398.             co = (self.prev.co + self.next.co)/2.0
  2399.         else:
  2400.             co = (cos[0]+cos[1])/2.0
  2401.         '''
  2402.         # Above can give odd results every now and then
  2403.         co = (self.prev.co + self.next.co)/2.0
  2404.         
  2405.         # Now apply
  2406.         factor_i = 1.0-factor
  2407.         self.setCo(self.co*factor_i  +  co*factor)
  2408.         self.radius = self.radius*factor_i  +  radius*factor
  2409.         
  2410.         return True
  2411.         
  2412.     def childPoint(self, index):
  2413.         '''
  2414.         Returns the middle point for any children between this and the next edge
  2415.         '''
  2416.         if self.next == None:
  2417.             raise 'Error'
  2418.         
  2419.         if index == 0:    return (self.getAbsVec(0) + self.next.getAbsVec(1)) / 2
  2420.         if index == 1:    return (self.getAbsVec(1) + self.next.getAbsVec(2)) / 2
  2421.         if index == 2:    return (self.getAbsVec(2) + self.next.getAbsVec(3)) / 2
  2422.         if index == 3:    return (self.getAbsVec(3) + self.next.getAbsVec(0)) / 2
  2423.     
  2424.     def childPointUnused(self, index):
  2425.         '''
  2426.         Same as above but return None when the point is alredy used.
  2427.         '''
  2428.         if self.children[index]:
  2429.             return None
  2430.         return self.childPoint(index)
  2431.         
  2432.     
  2433.     def roll(self, angle):
  2434.         '''
  2435.         Roll the quad about its normal 
  2436.         use for aurienting the sides of a quad to meet a branch that stems from here...
  2437.         '''
  2438.         # debugVec(self.co, self.co + self.no)
  2439.         
  2440.         mat = RotationMatrix(angle, 3, 'r', self.no)
  2441.         for i in xrange(4):
  2442.             self.vecs[i] = self.vecs[i] * mat
  2443.     
  2444.     
  2445.     def toMesh(self, mesh):
  2446.         self.verts[0].co = self.getAbsVec(0)
  2447.         self.verts[1].co = self.getAbsVec(1)
  2448.         self.verts[2].co = self.getAbsVec(2)
  2449.         self.verts[3].co = self.getAbsVec(3)
  2450.         
  2451.         if not self.next:
  2452.             return
  2453.         
  2454.         if self.prev == None and self.branch.parent_pt:
  2455.             # join from parent branch
  2456.             
  2457.             # which side are we of the parents quad
  2458.             index = self.branch.parent_pt.children.index(self.branch)
  2459.             
  2460.             # collect the points we are to merge into between the parent its next point
  2461.             if index==0:    verts = [self.branch.parent_pt.verts[0], self.branch.parent_pt.verts[1], self.branch.parent_pt.next.verts[1], self.branch.parent_pt.next.verts[0]]
  2462.             if index==1:    verts = [self.branch.parent_pt.verts[1], self.branch.parent_pt.verts[2], self.branch.parent_pt.next.verts[2], self.branch.parent_pt.next.verts[1]]
  2463.             if index==2:    verts = [self.branch.parent_pt.verts[2], self.branch.parent_pt.verts[3], self.branch.parent_pt.next.verts[3], self.branch.parent_pt.next.verts[2]]
  2464.             if index==3:    verts = [self.branch.parent_pt.verts[3], self.branch.parent_pt.verts[0], self.branch.parent_pt.next.verts[0], self.branch.parent_pt.next.verts[3]]
  2465.                 
  2466.                 
  2467.             # Watchout for overlapping faces!
  2468.             self.branch.faces[:] =\
  2469.                 [verts[0], verts[1], self.verts[1], self.verts[0]],\
  2470.                 [verts[1], verts[2], self.verts[2], self.verts[1]],\
  2471.                 [verts[2], verts[3], self.verts[3], self.verts[2]],\
  2472.                 [verts[3], verts[0], self.verts[0], self.verts[3]]
  2473.         
  2474.         # normal join, parents or no parents
  2475.         if not self.children[0]:    self.faces[0] = [self.verts[0], self.verts[1], self.next.verts[1], self.next.verts[0]]
  2476.         if not self.children[1]:    self.faces[1] = [self.verts[1], self.verts[2], self.next.verts[2], self.next.verts[1]]
  2477.         if not self.children[2]:    self.faces[2] = [self.verts[2], self.verts[3], self.next.verts[3], self.next.verts[2]]
  2478.         if not self.children[3]:    self.faces[3] = [self.verts[3], self.verts[0], self.next.verts[0], self.next.verts[3]]
  2479.     
  2480.     def calcVerts(self):
  2481.         if self.prev == None:
  2482.             if self.branch.parent_pt:
  2483.                 cross = self.no.cross(self.branch.parent_pt.no) * RotationMatrix(-45, 3, 'r', self.no)
  2484.             else:
  2485.                 # parentless branch - for best results get a cross thats not the same as the normal, in rare cases this happens.
  2486.                 
  2487.                 # Was just doing 
  2488.                 #  cross = zup
  2489.                 # which works most of the time, but no verticle lines
  2490.                 
  2491.                 if AngleBetweenVecsSafe(self.no, zup) > 1.0:    cross = zup
  2492.                 elif AngleBetweenVecsSafe(self.no, yup) > 1.0:    cross = yup
  2493.                 else:                                            cross = xup
  2494.                 
  2495.         else:
  2496.             cross = self.prev.vecs[0].cross(self.no)
  2497.         
  2498.         self.vecs[0] = self.no.cross(cross)
  2499.         self.vecs[0].length = abs(self.radius)
  2500.         mat = RotationMatrix(90, 3, 'r', self.no)
  2501.         self.vecs[1] = self.vecs[0] * mat
  2502.         self.vecs[2] = self.vecs[1] * mat
  2503.         self.vecs[3] = self.vecs[2] * mat
  2504.     
  2505.     def hasChildren(self):
  2506.         '''
  2507.         Use .childCount where possible, this does the real check
  2508.         '''
  2509.         if self.children.count(None) == 4:
  2510.             return False
  2511.         else:
  2512.             return True
  2513.     
  2514. class branch:
  2515.     def __init__(self):
  2516.         self.bpoints = []
  2517.         self.parent_pt = None
  2518.         self.tag = False # have we calculated our points
  2519.         self.face_cap = None
  2520.         self.length = -1
  2521.         # self.totchildren = 0
  2522.         # Bones per branch
  2523.         self.faces = [None, None, None, None]
  2524.         self.uv = None # face uvs can be fake, always 4
  2525.         self.bones = []
  2526.         self.generation = 0 # use to limit twig reproduction
  2527.         self.twig_count = 0 # count the number of twigs - so as to limit how many twigs a branch gets
  2528.         # self.myindex = -1
  2529.         ### self.segment_spacing_scale = 1.0 # use this to scale up the spacing - so small twigs dont get WAY too many polys
  2530.         self.type = None
  2531.     
  2532.     def __repr__(self):
  2533.         s = ''
  2534.         s += '\tbranch'
  2535.         s += '\tbpoints:', len(self.bpoints)
  2536.         for pt in brch.bpoints:
  2537.             s += str(self.pt)
  2538.     
  2539.     def getNormal(self):
  2540.         return (self.bpoints[-1].co - self.bpoints[0].co).normalize()
  2541.     
  2542.     def getParentAngle(self):
  2543.         if self.parent_pt:
  2544.             return AngleBetweenVecsSafe(self.parent_pt.no, self.bpoints[0].no )
  2545.         else:
  2546.             return 45.0
  2547.     
  2548.     def getParentRadiusRatio(self):
  2549.         if self.parent_pt:
  2550.             return self.bpoints[0].radius / self.parent_pt.radius
  2551.         else:
  2552.             return 0.8
  2553.     
  2554.     def getLength(self):
  2555.         return (self.bpoints[0].co - self.bpoints[-1].co).length
  2556.     
  2557.     def getStraightness(self):
  2558.         straight = 0.0
  2559.         pt = self.bpoints[0]
  2560.         while pt.next:
  2561.             straight += AngleBetweenVecsSafe(pt.no, pt.next.no)
  2562.             pt = pt.next
  2563.         return straight
  2564.         
  2565.     
  2566.     '''
  2567.     def calcTotChildren(self):
  2568.         for pt in self.bpoints:
  2569.             self.totchildren += pt.childCount
  2570.     '''
  2571.     def calcData(self):
  2572.         '''
  2573.         Finalize once point data is there
  2574.         '''
  2575.         self.calcPointLinkedList()
  2576.         self.calcPointExtras()
  2577.     
  2578.     def calcPointLinkedList(self):
  2579.         for i in xrange(1, len(self.bpoints)-1):
  2580.             self.bpoints[i].next = self.bpoints[i+1]
  2581.             self.bpoints[i].prev = self.bpoints[i-1]
  2582.         
  2583.         self.bpoints[0].next = self.bpoints[1]    
  2584.         self.bpoints[-1].prev = self.bpoints[-2]
  2585.         
  2586.     def calcPointExtras(self):
  2587.         '''
  2588.         Run on a new branch or after transforming an existing one.
  2589.         '''
  2590.         for pt in self.bpoints:
  2591.             pt.calcNormal()
  2592.             pt.calcNextMidCo()
  2593.     
  2594.     def calcTwigBounds(self, tree):
  2595.         '''
  2596.         Check if out points are 
  2597.         '''
  2598.         for pt in self.bpoints:
  2599.             pt.inTwigBounds = tree.isPointInTwigBounds(pt.co)
  2600.             #if pt.inTwigBounds:
  2601.             #    debug_pt(pt.co)
  2602.     
  2603.     def baseTrim(self, connect_base_trim):
  2604.         # if 1)    dont remove the whole branch, maybe an option but later
  2605.         # if 2)    we are alredy a parent, cant remove me now.... darn :/ not nice...
  2606.         #        could do this properly but it would be slower and its a corner case.
  2607.         #
  2608.         # if 3)    this point is within the branch, remove it.
  2609.         #        Scale this value by the difference in radius, a low trim looks better when the parent is a lot bigger..
  2610.         # 
  2611.         
  2612.         while    len(self.bpoints)>2 and\
  2613.                 self.bpoints[0].childCount == 0 and\
  2614.                 (self.parent_pt.nextMidCo - self.bpoints[0].co).length < ((self.parent_pt.radius + self.parent_pt.next.radius)/4) + (self.bpoints[0].radius * connect_base_trim):
  2615.             # Note /4 - is a bit odd, since /2 is correct, but /4 lets us have more tight joints by default
  2616.             
  2617.             
  2618.             del self.bpoints[0]
  2619.             self.bpoints[0].prev = None
  2620.     
  2621.     def boundsTrim(self):
  2622.         '''
  2623.         depends on calcTwigBounds running first. - also assumes no children assigned yet! make sure this is always the case.
  2624.         '''
  2625.         trim = False
  2626.         for i, pt in enumerate(self.bpoints):
  2627.             if not pt.inTwigBounds:
  2628.                 trim = True
  2629.                 break
  2630.         
  2631.         # We must have at least 2 points to be a valid branch. this will be a stump :/
  2632.         if not trim or i < 3:
  2633.             self.bpoints = [] # 
  2634.             return
  2635.         
  2636.         # Shorten the point list
  2637.         self.bpoints = self.bpoints[:i]
  2638.         self.bpoints[-1].makeLast()
  2639.     
  2640.     def taper(self, twig_ob_bounds_prune_taper = 0.0):
  2641.         l = float(len( self.bpoints ))
  2642.         for i, pt in enumerate(self.bpoints):
  2643.             pt.radius *= (((l-i)/l) + (twig_ob_bounds_prune_taper*(i/l)) )
  2644.     
  2645.     def getParentBranch(self):
  2646.         if not self.parent_pt:
  2647.             return None
  2648.         return self.parent_pt.branch
  2649.         
  2650.     def getParentQuadAngle(self):
  2651.         '''
  2652.         The angle off we are from our parent quad,
  2653.         '''
  2654.         # used to roll the parent so its faces us better
  2655.         
  2656.         # Warning this can be zero sometimes, see the try below for the error
  2657.         parent_normal = self.getParentFaceCent() - self.parent_pt.nextMidCo
  2658.         
  2659.         
  2660.         self_normal = self.bpoints[1].co - self.parent_pt.co
  2661.         # We only want the angle in relation to the parent points normal
  2662.         # modify self_normal to make this so
  2663.         cross = self_normal.cross(self.parent_pt.no)
  2664.         self_normal = self.parent_pt.no.cross(cross) # CHECK
  2665.         
  2666.         #try:    angle = AngleBetweenVecs(parent_normal, self_normal)
  2667.         #except:    return 0.0
  2668.         angle = AngleBetweenVecsSafe(parent_normal, self_normal)
  2669.         
  2670.         
  2671.         # see if we need to rotate positive or negative
  2672.         # USE DOT PRODUCT!
  2673.         cross = parent_normal.cross(self_normal)
  2674.         if AngleBetweenVecsSafe(cross, self.parent_pt.no) > 90:
  2675.             angle = -angle
  2676.         
  2677.         return angle
  2678.     
  2679.     def getParentQuadIndex(self):
  2680.         return self.parent_pt.children.index(self)
  2681.     def getParentFaceCent(self):
  2682.         return self.parent_pt.childPoint(  self.getParentQuadIndex()  )
  2683.     
  2684.     def findClosest(self, co):
  2685.         '''
  2686.         Find the closest point that can bare a child
  2687.         '''
  2688.         
  2689.         
  2690.         ''' # this dosnt work, but could.
  2691.         best = None
  2692.         best_dist = 100000000
  2693.         for pt in self.bpoints:    
  2694.             if pt.next:
  2695.                 co_on_line, fac = ClosestPointOnLine(co, pt.co, pt.next.co)
  2696.                 print fac
  2697.                 if fac >= 0.0 and fac <= 1.0:
  2698.                     
  2699.                     return pt, (co-co_on_line).length
  2700.         
  2701.         return best, best_dist
  2702.         '''
  2703.         best = None
  2704.         best_dist = 100000000
  2705.         for pt in self.bpoints:
  2706.             if pt.nextMidCo and pt.childCount < 4:
  2707.                 dist = (pt.nextMidCo-co).length
  2708.                 if dist < best_dist:
  2709.                     best = pt
  2710.                     best_dist = dist
  2711.         
  2712.         return best, best_dist
  2713.     
  2714.     def inParentChain(self, brch):
  2715.         '''
  2716.         See if this branch is a parent of self or in the chain
  2717.         '''
  2718.         
  2719.         self_parent_lookup = self.getParentBranch()
  2720.         while self_parent_lookup:
  2721.             if self_parent_lookup == brch:
  2722.                 return True
  2723.             self_parent_lookup = self_parent_lookup.getParentBranch()
  2724.         
  2725.         return False
  2726.     
  2727.     def transform(self, mat, loc=None, scale=None):
  2728.         if scale==None:
  2729.             scale = (xyzup * mat).length
  2730.         
  2731.         for pt in self.bpoints:
  2732.             if loc:
  2733.                 pt.co = (pt.co * mat) + loc
  2734.             else:
  2735.                 pt.co = pt.co * mat
  2736.             pt.radius *= scale
  2737.         
  2738.         for pt in self.bpoints:
  2739.             self.calcPointExtras()
  2740.     
  2741.     def translate(self, co):
  2742.         '''
  2743.         Simply move the twig on the branch
  2744.         '''
  2745.         ofs = self.bpoints[0].co-co
  2746.         for pt in self.bpoints:
  2747.             pt.co -= ofs
  2748.     
  2749.     def transformRecursive(self, tree, mat3x3, cent, scale=None):
  2750.         
  2751.         if scale==None:
  2752.             # incase this is a translation matrix
  2753.             scale = ((xyzup * mat3x3) - (Vector(0,0,0) * mat3x3)).length
  2754.         
  2755.         for pt in self.bpoints:        pt.co = ((pt.co-cent) * mat3x3) + cent
  2756.         #for pt in self.bpoints:        pt.co = (pt.co * mat3x3)
  2757.         for pt in self.bpoints:        self.calcPointExtras()
  2758.             
  2759.             
  2760.         for brch in tree.branches_all:
  2761.             if brch.parent_pt:
  2762.                 if brch.parent_pt.branch == self:
  2763.                     
  2764.                     brch.transformRecursive(tree, mat3x3, cent, scale)
  2765.             
  2766.         '''
  2767.         for pt in self.bpoints:
  2768.             for brch in pt.children:
  2769.                 if brch:
  2770.                     brch.transformRecursive(mat3x3, cent, scale)
  2771.         '''
  2772.     def bestTwigSegment(self):
  2773.         '''
  2774.         Return the most free part on the branch to place a new twig
  2775.         return (sort_value, best_index, self)
  2776.         '''
  2777.         
  2778.         # loop up and down the branch - counding how far from the last parent segment we are
  2779.         spacing1 = [0] * (len(self.bpoints)-1)
  2780.         spacing2 = spacing1[:]
  2781.         
  2782.         step_from_parent = 0
  2783.         for i in xrange(len(spacing1)): # -1 because the last pt cant have kits
  2784.             
  2785.             if self.bpoints[i].childCount or self.bpoints[i].inTwigBounds==False:
  2786.                 step_from_parent = 0
  2787.             else:
  2788.                 step_from_parent += 1
  2789.             
  2790.             spacing1[i] += step_from_parent # -1 because the last pt cant have kits
  2791.         
  2792.         best_index = -1
  2793.         best_val = -1
  2794.         step_from_parent = 0
  2795.         for i in xrange(len(spacing1)-1, -1, -1):
  2796.             
  2797.             if self.bpoints[i].childCount or self.bpoints[i].inTwigBounds==False:
  2798.                 step_from_parent = 0
  2799.             else:
  2800.                 step_from_parent += 1
  2801.             
  2802.             spacing2[i] += step_from_parent
  2803.             
  2804.             # inTwigBounds is true by default, when twigBounds are used it can be false
  2805.             if self.bpoints[i].childCount < 4 and self.bpoints[i].inTwigBounds:
  2806.                 # Dont allow to assign more verts then 4
  2807.                 val = spacing1[i] * spacing2[i]
  2808.                 if val > best_val:
  2809.                     best_val = val
  2810.                     best_index = i
  2811.         
  2812.         #if best_index == -1:
  2813.         #    raise "Error"
  2814.             
  2815.         # This value is only used for sorting, so the lower the value - the sooner it gets a twig.
  2816.         #sort_val = -best_val + (1/self.getLength())
  2817.         sort_val=self.getLength()
  2818.         
  2819.         return sort_val, best_index, self
  2820.     
  2821.     def evenPointDistrobution(self, factor=1.0, factor_joint=1.0):
  2822.         '''
  2823.         Redistribute points that are not evenly distributed
  2824.         factor is between 0.0 and 1.0
  2825.         '''
  2826.         
  2827.         for pt in self.bpoints:
  2828.             if pt.next and pt.prev and pt.childCount == 0 and pt.prev.childCount == 0:
  2829.                 w1 = pt.nextLength()
  2830.                 w2 = pt.prevLength()
  2831.                 wtot = w1+w2
  2832.                 if wtot > 0.0:
  2833.                     w1=w1/wtot
  2834.                     #w2=w2/wtot
  2835.                     w1 = abs(w1-0.5)*2 # make this from 0.0 to 1.0, where 0 is the middle and 1.0 is as far out of the middle as possible.
  2836.                     # print "%.6f" % w1
  2837.                     pt.smooth(w1*factor, w1*factor_joint)
  2838.     
  2839.     def fixOverlapError(self, joint_smooth=1.0):
  2840.         # Keep fixing until no hasOverlapError left to fix.
  2841.         
  2842.         error = True
  2843.         while error:
  2844.             error = False
  2845.             for pt in self.bpoints:
  2846.                 if pt.prev and pt.next:
  2847.                     if pt.hasOverlapError():
  2848.                         if pt.smooth(1.0, joint_smooth): # if we cant fix then dont bother trying again.
  2849.                             error = True
  2850.     
  2851.     def evenJointDistrobution(self, joint_compression = 1.0):
  2852.         # See if we need to evaluate this branch at all 
  2853.         if len(self.bpoints) <= 2: # Rare but in this case we cant do anything
  2854.             return
  2855.         has_children = False
  2856.         for pt in self.bpoints:
  2857.             if pt.childCount:
  2858.                 has_children = True
  2859.                 break
  2860.         
  2861.         if not has_children:
  2862.             return
  2863.         
  2864.         # OK, we have children, so we have some work to do...
  2865.         # center each segment
  2866.         
  2867.         # work out the median location of all points children.
  2868.         for pt in self.bpoints:
  2869.             pt.calcChildrenMidData()
  2870.             pt.targetCos[:] = []
  2871.         
  2872.         for pt in self.bpoints:
  2873.             
  2874.             if pt.childrenMidCo:
  2875.                 # Move this and the next segment to be around the child point.
  2876.                 # TODO - factor in the branch angle, be careful with this - close angles can have extreme values.
  2877.                 slide_dist = (pt.childrenMidCo - pt.co).length - (pt.childrenMidRadius * joint_compression)
  2878.                 co = pt.slideCo( slide_dist )
  2879.                 if co:
  2880.                     pt.targetCos.append( co )
  2881.                 
  2882.                 slide_dist = (pt.childrenMidRadius * joint_compression) - (pt.childrenMidCo - pt.next.co).length
  2883.                 co = pt.next.slideCo( slide_dist )
  2884.                 if co:
  2885.                     pt.next.targetCos.append( co )
  2886.         
  2887.         for pt in reversed(self.bpoints):
  2888.             pt.applyTargetLocation()
  2889.     
  2890.     def collapsePoints(self, seg_density=0.5, seg_density_angle=20.0, seg_density_radius=0.3, smooth_joint=1.0):
  2891.         
  2892.         collapse = True
  2893.         while collapse:
  2894.             collapse = False
  2895.             pt = self.bpoints[0]
  2896.             while pt:
  2897.                 # Collapse angles greater then 90. they are useually artifacts
  2898.                 
  2899.                 if pt.prev and pt.next and pt.prev.childCount == 0:
  2900.                     if (pt.radius + pt.prev.radius) != 0.0 and abs(pt.radius - pt.prev.radius) / (pt.radius + pt.prev.radius) < seg_density_radius:
  2901.                         ang = AngleBetweenVecsSafe(pt.no, pt.prev.no)
  2902.                         if seg_density_angle == 180 or ang > 90 or ang < seg_density_angle:
  2903.                             ## if (pt.prev.nextMidCo-pt.co).length < ((pt.radius + pt.prev.radius)/2) * seg_density:
  2904.                             if (pt.prev.nextMidCo-pt.co).length < seg_density or ang > 90:
  2905.                                 pt_save = pt.prev
  2906.                                 if pt.next.collapseUp(): # collapse this point
  2907.                                     collapse = True
  2908.                                     pt = pt_save # so we never reference a removed point
  2909.                 
  2910.                 if pt.childCount == 0 and pt.next: #if pt.childrenMidCo == None:
  2911.                     if (pt.radius + pt.next.radius) != 0.0 and abs(pt.radius - pt.next.radius) / (pt.radius + pt.next.radius) < seg_density_radius:
  2912.                         ang = AngleBetweenVecsSafe(pt.no, pt.next.no)
  2913.                         if seg_density_angle == 180 or ang > 90 or ang < seg_density_angle:
  2914.                             # do here because we only want to run this on points with no children,
  2915.                             # Are we closer theto eachother then the radius?
  2916.                             ## if (pt.nextMidCo-pt.co).length < ((pt.radius + pt.next.radius)/2) * seg_density:
  2917.                             if (pt.nextMidCo-pt.co).length < seg_density or ang > 90:
  2918.                                 if pt.collapseDown():
  2919.                                     collapse = True
  2920.                 
  2921.                 pt = pt.next
  2922.         ## self.checkPointList()
  2923.         self.evenPointDistrobution(1.0, smooth_joint)
  2924.         
  2925.         for pt in self.bpoints:
  2926.             pt.calcNormal()
  2927.             pt.calcNextMidCo()
  2928.     
  2929.     # This is a bit dodgy - moving the branches around after placing can cause problems
  2930.     """
  2931.     def branchReJoin(self):
  2932.         '''
  2933.         Not needed but nice to run after collapsing incase segments moved a lot
  2934.         '''
  2935.         if not self.parent_pt:
  2936.             return # nothing to do
  2937.         
  2938.         # see if the next segment is closer now (after collapsing)
  2939.         parent_pt = self.parent_pt
  2940.         root_pt = self.bpoints[0]
  2941.         
  2942.         #try:
  2943.         index = parent_pt.children.index(self)
  2944.         #except:
  2945.         #print "This is bad!, but not being able to re-join isnt that big a deal"
  2946.         
  2947.         current_dist = (parent_pt.nextMidCo - root_pt.co).length
  2948.         
  2949.         # TODO - Check size of new area is ok to move into
  2950.         
  2951.         if parent_pt.next and parent_pt.next.next and parent_pt.next.children[index] == None:
  2952.             # We can go here if we want, see if its better
  2953.             if current_dist > (parent_pt.next.nextMidCo - root_pt.co).length:
  2954.                 self.parent_pt.children[index] = None
  2955.                 self.parent_pt.childCount -= 1
  2956.                 
  2957.                 self.parent_pt = parent_pt.next
  2958.                 self.parent_pt.children[index] = self
  2959.                 self.parent_pt.childCount += 1
  2960.                 return
  2961.         
  2962.         if parent_pt.prev and parent_pt.prev.children[index] == None:
  2963.             # We can go here if we want, see if its better
  2964.             if current_dist > (parent_pt.prev.nextMidCo - root_pt.co).length:
  2965.                 self.parent_pt.children[index] = None
  2966.                 self.parent_pt.childCount -= 1
  2967.                 
  2968.                 self.parent_pt = parent_pt.prev
  2969.                 self.parent_pt.children[index] = self
  2970.                 self.parent_pt.childCount += 1
  2971.                 return
  2972.     """
  2973.     
  2974.     def checkPointList(self):
  2975.         '''
  2976.         Error checking. use to check if collapsing worked.
  2977.         '''
  2978.         p_link = self.bpoints[0]
  2979.         i = 0
  2980.         while p_link:
  2981.             if self.bpoints[i] != p_link:
  2982.                 raise "Error"
  2983.             
  2984.             if p_link.prev and p_link.prev != self.bpoints[i-1]:
  2985.                 raise "Error Prev"
  2986.             
  2987.             if p_link.next and p_link.next != self.bpoints[i+1]:
  2988.                 raise "Error Next"
  2989.             
  2990.             p_link = p_link.next
  2991.             i+=1
  2992.     
  2993.     def mixToNew(self, other, BLEND_MODE):
  2994.         '''
  2995.         Generate a new branch based on 2 existing ones
  2996.         These branches will point 'zup' - aurient 'xup' and have a tip length of 1.0
  2997.         '''
  2998.         
  2999.         # Lets be lazy! - if the branches are different sizes- use the shortest.
  3000.         # brch1 is always smaller
  3001.         
  3002.         brch1 = self
  3003.         brch2 = other
  3004.         if len(brch1.bpoints) > len(brch2.bpoints):
  3005.             brch1, brch2 = brch2, brch1
  3006.         
  3007.         if len(brch1.bpoints) == 1:
  3008.             return None
  3009.         
  3010.         co_start = brch1.bpoints[0].co
  3011.         cos1 = [ pt.co - co_start for pt in brch1.bpoints ]
  3012.         
  3013.         co_start = brch2.bpoints[0].co
  3014.         if len(brch1.bpoints) == len(brch2.bpoints):
  3015.             cos2 = [ pt.co - co_start for pt in brch2.bpoints ]
  3016.         else: # truncate the points
  3017.             cos2 = [ brch2.bpoints[i].co - co_start for i in xrange(len(brch1.bpoints)) ]
  3018.             
  3019.         scales = []
  3020.         for cos_ls in (cos1, cos2):
  3021.             cross = cos_ls[-1].cross(zup)
  3022.             mat = RotationMatrix(AngleBetweenVecsSafe(cos_ls[-1], zup), 3, 'r', cross)
  3023.             cos_ls[:] = [co*mat for co in cos_ls]
  3024.         
  3025.             # point z-up
  3026.             
  3027.             # Now they are both pointing the same way aurient the curves to be rotated the same way
  3028.             xy_nor = Vector(0,0,0)
  3029.             for co in cos_ls:
  3030.                 xy_nor.x += co.x
  3031.                 xy_nor.y += co.y
  3032.             cross = xy_nor.cross(xup)
  3033.             
  3034.             # Also scale them here so they are 1.0 tall always
  3035.             scale = 1.0/(cos_ls[0]-cos_ls[-1]).length
  3036.             mat = RotationMatrix(AngleBetweenVecsSafe(xy_nor, xup), 3, 'r', cross) * Matrix([scale,0,0],[0,scale,0],[0,0,scale])
  3037.             cos_ls[:] = [co*mat for co in cos_ls]
  3038.             
  3039.             scales.append(scale)
  3040.         
  3041.         # Make the new branch
  3042.         new_brch = branch()
  3043.         new_brch.type = BRANCH_TYPE_GROWN
  3044.         for i in xrange(len(cos1)):
  3045.             new_brch.bpoints.append( bpoint(new_brch, (cos1[i]+cos2[i])*0.5, Vector(), (brch1.bpoints[i].radius*scales[0] + brch2.bpoints[i].radius*scales[1])/2) )
  3046.         
  3047.         new_brch.calcData()
  3048.         return new_brch
  3049.     
  3050.     '''
  3051.     def toMesh(self):
  3052.         pass
  3053.     '''
  3054.  
  3055.  
  3056.  
  3057.  
  3058. # No GUI code above this! ------------------------------------------------------
  3059.  
  3060. # PREFS - These can be saved on the object's id property. use 'tree2curve' slot
  3061. from Blender import Draw
  3062. import BPyWindow
  3063. ID_SLOT_NAME = 'Curve2Tree'
  3064.  
  3065. EVENT_NONE = 0
  3066. EVENT_EXIT = 1
  3067. EVENT_UPDATE = 2
  3068. EVENT_UPDATE_AND_UI = 2
  3069. EVENT_REDRAW = 3
  3070.  
  3071.  
  3072. # Prefs for each tree
  3073. PREFS = {}
  3074. PREFS['connect_sloppy'] = Draw.Create(1.5)
  3075. PREFS['connect_base_trim'] = Draw.Create(1.0)
  3076. PREFS['seg_density'] = Draw.Create(0.5)
  3077. PREFS['seg_density_angle'] = Draw.Create(20.0)
  3078. PREFS['seg_density_radius'] = Draw.Create(0.3)
  3079. PREFS['seg_joint_compression'] = Draw.Create(1.0)
  3080. PREFS['seg_joint_smooth'] = Draw.Create(2.0)
  3081. PREFS['image_main'] = Draw.Create('')
  3082. PREFS['do_uv'] = Draw.Create(0)
  3083. PREFS['uv_x_scale'] = Draw.Create(4.0)
  3084. PREFS['uv_y_scale'] = Draw.Create(1.0)
  3085. PREFS['do_material'] = Draw.Create(0)
  3086. PREFS['material_use_existing'] = Draw.Create(1)
  3087. PREFS['material_texture'] = Draw.Create(1)
  3088. PREFS['material_stencil'] = Draw.Create(1)
  3089. PREFS['do_subsurf'] = Draw.Create(1)
  3090. PREFS['do_cap_ends'] = Draw.Create(0)
  3091. PREFS['do_uv_keep_vproportion'] = Draw.Create(1)
  3092. PREFS['do_uv_vnormalize'] = Draw.Create(0)
  3093. PREFS['do_uv_uscale'] = Draw.Create(0)
  3094. PREFS['do_armature'] = Draw.Create(0)
  3095. PREFS['do_anim'] = Draw.Create(1)
  3096. try:        PREFS['anim_tex'] = Draw.Create([tex for tex in bpy.data.textures][0].name)
  3097. except:        PREFS['anim_tex'] = Draw.Create('')
  3098.  
  3099. PREFS['anim_speed'] = Draw.Create(0.2)
  3100. PREFS['anim_magnitude'] = Draw.Create(0.2)
  3101. PREFS['anim_speed_size_scale'] = Draw.Create(1)
  3102. PREFS['anim_offset_scale'] = Draw.Create(1.0)
  3103.  
  3104. PREFS['do_twigs_fill'] = Draw.Create(0)
  3105. PREFS['twig_fill_levels'] = Draw.Create(4)
  3106.  
  3107. PREFS['twig_fill_rand_scale'] = Draw.Create(0.1)
  3108. PREFS['twig_fill_fork_angle_max'] = Draw.Create(180.0)
  3109. PREFS['twig_fill_radius_min'] = Draw.Create(0.001)
  3110. PREFS['twig_fill_radius_factor'] = Draw.Create(0.75)
  3111. PREFS['twig_fill_shape_type'] = Draw.Create(1)
  3112. PREFS['twig_fill_shape_rand'] = Draw.Create(0.5)
  3113. PREFS['twig_fill_shape_power'] = Draw.Create(0.5)
  3114.  
  3115. PREFS['do_twigs'] = Draw.Create(0)
  3116. PREFS['twig_ratio'] = Draw.Create(2.0)
  3117. PREFS['twig_select_mode'] = Draw.Create(0)
  3118. PREFS['twig_select_factor'] = Draw.Create(0.5)
  3119. PREFS['twig_scale'] = Draw.Create(0.8)
  3120. PREFS['twig_scale_width'] = Draw.Create(1.0)
  3121. PREFS['twig_random_orientation'] = Draw.Create(180)
  3122. PREFS['twig_random_angle'] = Draw.Create(33)
  3123. PREFS['twig_recursive'] = Draw.Create(1)
  3124. PREFS['twig_recursive_limit'] = Draw.Create(3)
  3125. PREFS['twig_ob_bounds'] = Draw.Create('') # WATCH out, used for do_twigs_fill AND do_twigs
  3126. PREFS['twig_ob_bounds_prune'] = Draw.Create(1)
  3127. PREFS['twig_ob_bounds_prune_taper'] = Draw.Create(1.0)
  3128. PREFS['twig_placement_maxradius'] = Draw.Create(10.0)
  3129. PREFS['twig_placement_maxtwig'] = Draw.Create(4)
  3130. PREFS['twig_follow_parent'] = Draw.Create(0.0)
  3131. PREFS['twig_follow_x'] = Draw.Create(0.0)
  3132. PREFS['twig_follow_y'] = Draw.Create(0.0)
  3133. PREFS['twig_follow_z'] = Draw.Create(0.0)
  3134.  
  3135. PREFS['do_leaf'] = Draw.Create(0)
  3136.  
  3137. PREFS['leaf_branch_limit'] = Draw.Create(0.25)
  3138. PREFS['leaf_branch_limit_rand'] = Draw.Create(0.1)
  3139. PREFS['leaf_branch_density'] = Draw.Create(0.1)
  3140. PREFS['leaf_branch_pitch_angle'] = Draw.Create(0.0)
  3141. PREFS['leaf_branch_pitch_rand'] = Draw.Create(0.2)
  3142. PREFS['leaf_branch_roll_rand'] = Draw.Create(0.2)
  3143. PREFS['leaf_branch_angle'] = Draw.Create(75.0)
  3144. PREFS['leaf_rand_seed'] = Draw.Create(1.0)
  3145. PREFS['leaf_size'] = Draw.Create(0.5)
  3146. PREFS['leaf_size_rand'] = Draw.Create(0.5)
  3147.  
  3148. PREFS['leaf_object'] = Draw.Create('')
  3149.  
  3150. PREFS['do_variation'] = Draw.Create(0)
  3151. PREFS['variation_seed'] = Draw.Create(1)
  3152. PREFS['variation_orientation'] = Draw.Create(0.0)
  3153. PREFS['variation_scale'] = Draw.Create(0.0)
  3154.  
  3155. GLOBAL_PREFS = {}
  3156. GLOBAL_PREFS['realtime_update'] = Draw.Create(0)
  3157.  
  3158.  
  3159. def getContextCurveObjects():
  3160.     sce = bpy.data.scenes.active
  3161.     objects = []
  3162.     ob_act = sce.objects.active
  3163.     for ob in sce.objects.context:
  3164.         if ob == ob_act: ob_act = None
  3165.         
  3166.         if ob.type != 'Curve':
  3167.             ob = ob.parent
  3168.         if not ob or ob.type != 'Curve':
  3169.             continue
  3170.         objects.append(ob)
  3171.         
  3172.         # Alredy delt with 
  3173.         
  3174.     
  3175.     # Add the active, important when using localview or local layers
  3176.     if ob_act:
  3177.         ob = ob_act
  3178.         if ob.type != 'Curve':
  3179.             ob = ob.parent
  3180.         if not ob or ob.type != 'Curve':
  3181.             pass
  3182.         else:
  3183.             objects.append(ob)
  3184.     
  3185.     return objects
  3186.  
  3187.  
  3188. def Prefs2Dict(prefs, new_prefs):
  3189.     '''
  3190.     Make a copy with no button settings
  3191.     '''
  3192.     new_prefs.clear()
  3193.     for key, val in prefs.items():
  3194.         try:    new_prefs[key] = val.val
  3195.         except:    new_prefs[key] = val
  3196.     return new_prefs
  3197.  
  3198. def Dict2Prefs(prefs, new_prefs):
  3199.     '''
  3200.     Make a copy with button settings
  3201.     '''
  3202.     for key in prefs: # items would be nice for id groups
  3203.         val = prefs[key]
  3204.         ok = True
  3205.         
  3206.         try:
  3207.             # If we have this setting allredy but its a different type, use the old setting (converting int's to floats for instance)
  3208.             new_val = new_prefs[key] # this may fail, thats ok
  3209.             if (type(new_val)==Blender.Types.ButtonType) and (type(new_val.val) != type(val)):
  3210.                 ok = False
  3211.         except:
  3212.             pass
  3213.         
  3214.         if ok:
  3215.             try:
  3216.                 new_prefs[key] = Blender.Draw.Create( val )
  3217.             except:
  3218.                 new_prefs[key] = val
  3219.         
  3220.     return new_prefs
  3221.  
  3222. def Prefs2IDProp(idprop, prefs):
  3223.     new_prefs = {}
  3224.     Prefs2Dict(prefs, new_prefs)
  3225.     try:    del idprop[ID_SLOT_NAME]
  3226.     except:    pass
  3227.     
  3228.     idprop[ID_SLOT_NAME] = new_prefs
  3229.     
  3230. def IDProp2Prefs(idprop, prefs):
  3231.     try:
  3232.         prefs = idprop[ID_SLOT_NAME]
  3233.     except:
  3234.         return False
  3235.     Dict2Prefs(prefs, PREFS)
  3236.     return True
  3237.  
  3238. def buildTree(ob_curve, single=False):
  3239.     '''
  3240.     Must be a curve object, write to a child mesh
  3241.     Must check this is a curve object!
  3242.     '''
  3243.     print 'Curve2Tree, starting...'
  3244.     # if were only doing 1 object, just use the current prefs
  3245.     prefs = {}
  3246.     
  3247.     if single or not (IDProp2Prefs(ob_curve.properties, prefs)):
  3248.         prefs = PREFS
  3249.         
  3250.     
  3251.     # Check prefs are ok.
  3252.     
  3253.     
  3254.     sce = bpy.data.scenes.active
  3255.     
  3256.     def getObChild(parent, obtype):
  3257.         try:
  3258.             return [ _ob for _ob in sce.objects if _ob.type == obtype if _ob.parent == parent ][0]
  3259.         except:
  3260.             return None
  3261.     
  3262.     def newObChild(parent, obdata):
  3263.         
  3264.         ob_new = bpy.data.scenes.active.objects.new(obdata)
  3265.         # ob_new.Layers = parent.Layers
  3266.         
  3267.         # new object settings
  3268.         parent.makeParent([ob_new])
  3269.         ob_new.setMatrix(Matrix())
  3270.         ob_new.sel = 0
  3271.         return ob_new
  3272.     
  3273.     def hasModifier(modtype):
  3274.         return len([mod for mod in ob_mesh.modifiers if mod.type == modtype]) > 0
  3275.             
  3276.     
  3277.     sce = bpy.data.scenes.active
  3278.     
  3279.     if PREFS['image_main'].val:
  3280.         try:        image = bpy.data.images[PREFS['image_main'].val]
  3281.         except:        image = None
  3282.     else:            image = None
  3283.     
  3284.     # Get the mesh child
  3285.     
  3286.     print '\treading blenders curves...',
  3287.     time1 = Blender.sys.time()
  3288.     
  3289.     t = tree()
  3290.     t.fromCurve(ob_curve)
  3291.     if not t.branches_all:
  3292.         return # Empty curve? - may as well not throw an error
  3293.     
  3294.     time2 = Blender.sys.time() # time print
  3295.     """
  3296.     print '%.4f sec' % (time2-time1)
  3297.     if PREFS['do_twigs'].val:
  3298.         print '\tbuilding twigs...',
  3299.         t.buildTwigs(ratio=PREFS['twig_ratio'].val)
  3300.         time3 = Blender.sys.time() # time print
  3301.         print '%.4f sec' % (time3 - time2)
  3302.     """
  3303.     if 0: pass
  3304.     else:
  3305.         time3 = Blender.sys.time() # time print
  3306.     
  3307.     print '\tconnecting branches...',
  3308.     
  3309.     twig_ob_bounds = getObFromName(PREFS['twig_ob_bounds'].val)
  3310.     
  3311.     t.buildConnections(\
  3312.         sloppy = PREFS['connect_sloppy'].val,\
  3313.         connect_base_trim = PREFS['connect_base_trim'].val,\
  3314.         do_twigs = PREFS['do_twigs'].val,\
  3315.         twig_ratio = PREFS['twig_ratio'].val,\
  3316.         twig_select_mode = PREFS['twig_select_mode'].val,\
  3317.         twig_select_factor = PREFS['twig_select_factor'].val,\
  3318.         twig_scale = PREFS['twig_scale'].val,\
  3319.         twig_scale_width = PREFS['twig_scale_width'].val,\
  3320.         twig_random_orientation = PREFS['twig_random_orientation'].val,\
  3321.         twig_random_angle = PREFS['twig_random_angle'].val,\
  3322.         twig_recursive = PREFS['twig_recursive'].val,\
  3323.         twig_recursive_limit = PREFS['twig_recursive_limit'].val,\
  3324.         twig_ob_bounds = twig_ob_bounds,\
  3325.         twig_ob_bounds_prune = PREFS['twig_ob_bounds_prune'].val,\
  3326.         twig_ob_bounds_prune_taper = PREFS['twig_ob_bounds_prune_taper'].val,\
  3327.         twig_placement_maxradius = PREFS['twig_placement_maxradius'].val,\
  3328.         twig_placement_maxtwig = PREFS['twig_placement_maxtwig'].val,\
  3329.         twig_follow_parent = PREFS['twig_follow_parent'].val,\
  3330.         twig_follow_x = PREFS['twig_follow_x'].val,\
  3331.         twig_follow_y = PREFS['twig_follow_y'].val,\
  3332.         twig_follow_z = PREFS['twig_follow_z'].val,\
  3333.         do_variation = PREFS['do_variation'].val,\
  3334.         variation_seed = PREFS['variation_seed'].val,\
  3335.         variation_orientation = PREFS['variation_orientation'].val,\
  3336.         variation_scale = PREFS['variation_scale'].val,\
  3337.         do_twigs_fill = PREFS['do_twigs_fill'].val,\
  3338.         twig_fill_levels = PREFS['twig_fill_levels'].val,\
  3339.         twig_fill_rand_scale = PREFS['twig_fill_rand_scale'].val,\
  3340.         twig_fill_fork_angle_max = PREFS['twig_fill_fork_angle_max'].val,\
  3341.         twig_fill_radius_min = PREFS['twig_fill_radius_min'].val,\
  3342.         twig_fill_radius_factor = PREFS['twig_fill_radius_factor'].val,\
  3343.         twig_fill_shape_type = PREFS['twig_fill_shape_type'].val,\
  3344.         twig_fill_shape_rand = PREFS['twig_fill_shape_rand'].val,\
  3345.         twig_fill_shape_power = PREFS['twig_fill_shape_power'].val,\
  3346.     )
  3347.     
  3348.     time4 = Blender.sys.time() # time print
  3349.     print '%.4f sec' % (time4-time3)
  3350.     print '\toptimizing point spacing...',
  3351.     
  3352.     t.optimizeSpacing(\
  3353.         seg_density=PREFS['seg_density'].val,\
  3354.         seg_density_angle=PREFS['seg_density_angle'].val,\
  3355.         seg_density_radius=PREFS['seg_density_radius'].val,\
  3356.         joint_compression = PREFS['seg_joint_compression'].val,\
  3357.         joint_smooth = PREFS['seg_joint_smooth'].val\
  3358.     )
  3359.     
  3360.     time5 = Blender.sys.time() # time print
  3361.     print '%.4f sec' % (time5-time4)
  3362.     print '\tbuilding mesh...',
  3363.     
  3364.     ob_mesh = getObChild(ob_curve, 'Mesh')
  3365.     if not ob_mesh:
  3366.         # New object
  3367.         mesh = bpy.data.meshes.new('tree_' + ob_curve.name)
  3368.         ob_mesh = newObChild(ob_curve, mesh)
  3369.         # do subsurf later
  3370.     
  3371.     else:
  3372.         # Existing object
  3373.         mesh = ob_mesh.getData(mesh=1)
  3374.         ob_mesh.setMatrix(Matrix())
  3375.     
  3376.     # Do we need a do_uv_blend_layer?
  3377.     if PREFS['do_material'].val and PREFS['material_stencil'].val and PREFS['material_texture'].val:
  3378.         do_uv_blend_layer = True
  3379.     else:
  3380.         do_uv_blend_layer = False
  3381.     
  3382.     mesh = t.toMesh(mesh,\
  3383.         do_uv = PREFS['do_uv'].val,\
  3384.         uv_image = image,\
  3385.         do_uv_keep_vproportion = PREFS['do_uv_keep_vproportion'].val,\
  3386.         do_uv_vnormalize = PREFS['do_uv_vnormalize'].val,\
  3387.         do_uv_uscale = PREFS['do_uv_uscale'].val,\
  3388.         uv_x_scale = PREFS['uv_x_scale'].val,\
  3389.         uv_y_scale = PREFS['uv_y_scale'].val,\
  3390.         do_uv_blend_layer = do_uv_blend_layer,\
  3391.         do_cap_ends = PREFS['do_cap_ends'].val
  3392.     )
  3393.     
  3394.     if PREFS['do_leaf'].val:
  3395.         ob_leaf_dupliface = getObChild(ob_mesh, 'Mesh')
  3396.         if not ob_leaf_dupliface: # New object
  3397.             mesh_leaf = bpy.data.meshes.new('leaf_' + ob_curve.name)
  3398.             ob_leaf_dupliface = newObChild(ob_mesh, mesh_leaf)
  3399.         else:
  3400.             mesh_leaf = ob_leaf_dupliface.getData(mesh=1)
  3401.             ob_leaf_dupliface.setMatrix(Matrix())
  3402.         
  3403.         leaf_object = getObFromName(PREFS['leaf_object'].val)
  3404.  
  3405.         mesh_leaf = t.toLeafMesh(mesh_leaf,\
  3406.             leaf_branch_limit = PREFS['leaf_branch_limit'].val,\
  3407.             leaf_branch_limit_rand = PREFS['leaf_branch_limit_rand'].val,\
  3408.             leaf_size = PREFS['leaf_size'].val,\
  3409.             leaf_size_rand = PREFS['leaf_size_rand'].val,\
  3410.             leaf_branch_density = PREFS['leaf_branch_density'].val,\
  3411.             leaf_branch_pitch_angle = PREFS['leaf_branch_pitch_angle'].val,\
  3412.             leaf_branch_pitch_rand = PREFS['leaf_branch_pitch_rand'].val,\
  3413.             leaf_branch_roll_rand = PREFS['leaf_branch_roll_rand'].val,\
  3414.             leaf_branch_angle = PREFS['leaf_branch_angle'].val,\
  3415.             leaf_rand_seed = PREFS['leaf_rand_seed'].val,\
  3416.             leaf_object = leaf_object,\
  3417.         )
  3418.         
  3419.         if leaf_object:
  3420.             ob_leaf_dupliface.enableDupFaces = True
  3421.             ob_leaf_dupliface.enableDupFacesScale = True
  3422.             ob_leaf_dupliface.makeParent([leaf_object], 1)
  3423.         else:
  3424.             ob_leaf_dupliface.enableDupFaces = False
  3425.     
  3426.     mesh.calcNormals()
  3427.     
  3428.     if PREFS['do_material'].val:
  3429.         
  3430.         materials = mesh.materials
  3431.         if PREFS['material_use_existing'].val and materials:
  3432.             t.material = materials[0]
  3433.         else:
  3434.             t.material = bpy.data.materials.new(ob_curve.name)
  3435.             mesh.materials = [t.material]
  3436.         
  3437.         if PREFS['material_texture'].val:
  3438.             
  3439.             # Set up the base image texture
  3440.             t.texBase = bpy.data.textures.new('base_' + ob_curve.name)
  3441.             t.material.setTexture(0, t.texBase, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.COL)
  3442.             t.texBase.type = Blender.Texture.Types.IMAGE
  3443.             if image:
  3444.                 t.texBase.image = image
  3445.             t.texBaseMTex = t.material.getTextures()[0]
  3446.             t.texBaseMTex.uvlayer = 'base'
  3447.             
  3448.             if PREFS['material_stencil'].val:
  3449.                 # Set up the blend texture
  3450.                 t.texBlend = bpy.data.textures.new('blend_' + ob_curve.name)
  3451.                 t.material.setTexture(1, t.texBlend, Blender.Texture.TexCo.UV, 0) # map to None
  3452.                 t.texBlend.type = Blender.Texture.Types.BLEND
  3453.                 t.texBlend.flags |= Blender.Texture.Flags.FLIPBLEND
  3454.                 t.texBlendMTex = t.material.getTextures()[1]
  3455.                 t.texBlendMTex.stencil = True
  3456.                 t.texBlendMTex.uvlayer = 'blend'
  3457.                 
  3458.                 
  3459.                 # Now make the texture for the stencil to blend, can reuse texBase here, jus tdifferent settings for the mtex
  3460.                 t.material.setTexture(2, t.texBase, Blender.Texture.TexCo.UV, Blender.Texture.MapTo.COL)
  3461.                 t.texJoinMTex = t.material.getTextures()[2]
  3462.                 t.texJoinMTex.uvlayer = 'join'
  3463.                 
  3464.                 # Add a UV layer for blending
  3465.                 
  3466.                 
  3467.     
  3468.     
  3469.     time6 = Blender.sys.time() # time print
  3470.     print '%.4f sec' % (time6-time5)
  3471.     
  3472.     # Do armature stuff....
  3473.     if PREFS['do_armature'].val:
  3474.         
  3475.         print '\tbuilding armature & animation...',
  3476.         
  3477.         ob_arm = getObChild(ob_curve, 'Armature')
  3478.         if ob_arm:
  3479.             armature = ob_arm.data
  3480.             ob_arm.setMatrix(Matrix())
  3481.         else:
  3482.             armature = bpy.data.armatures.new()
  3483.             ob_arm = newObChild(ob_curve, armature)
  3484.         
  3485.         t.toArmature(ob_arm, armature)
  3486.         
  3487.         # Add the modifier.
  3488.         if not hasModifier(Blender.Modifier.Types.ARMATURE):
  3489.             mod = ob_mesh.modifiers.append(Blender.Modifier.Types.ARMATURE)
  3490.             
  3491.             # TODO - assigne object anyway, even if an existing modifier exists.
  3492.             mod[Blender.Modifier.Settings.OBJECT] = ob_arm
  3493.         
  3494.         if PREFS['do_anim'].val:
  3495.             try:
  3496.                 tex = bpy.data.textures[PREFS['anim_tex'].val]
  3497.             except:
  3498.                 tex = None
  3499.                 Blender.Draw.PupMenu('error no texture, cannot animate bones')
  3500.             
  3501.             if tex:
  3502.                 t.toAction(ob_arm, tex,\
  3503.                         anim_speed = PREFS['anim_speed'].val,\
  3504.                         anim_magnitude = PREFS['anim_magnitude'].val,\
  3505.                         anim_speed_size_scale= PREFS['anim_speed_size_scale'].val,\
  3506.                         anim_offset_scale=PREFS['anim_offset_scale'].val
  3507.                         )
  3508.         
  3509.         time7 = Blender.sys.time() # time print
  3510.         print '%.4f sec\n' % (time7-time6)
  3511.     else:
  3512.         time7 = Blender.sys.time() # time print
  3513.     
  3514.     print 'done in %.4f sec' % (time7 - time1)
  3515.     
  3516.     # Add subsurf last it needed. so armature skinning is done first.
  3517.     # Do subsurf?
  3518.     if PREFS['do_subsurf'].val:
  3519.         if not hasModifier(Blender.Modifier.Types.SUBSURF):
  3520.             mod = ob_mesh.modifiers.append(Blender.Modifier.Types.SUBSURF)
  3521.             
  3522.     #ob_mesh.makeDisplayList()
  3523.     #mesh.update()
  3524.     bpy.data.scenes.active.update()
  3525.  
  3526. def do_pref_read(e=0,v=0, quiet=False):
  3527.     '''
  3528.     We dont care about e and v values, only there because its a callback
  3529.     '''
  3530.     sce = bpy.data.scenes.active
  3531.     ob = sce.objects.active
  3532.     
  3533.     if not ob:
  3534.         if not quiet:
  3535.             Blender.Draw.PupMenu('No active curve object')
  3536.         return
  3537.     
  3538.     if ob.type != 'Curve':
  3539.         ob = ob.parent
  3540.     
  3541.     if ob == None or ob.type != 'Curve':
  3542.         if not quiet:
  3543.             Blender.Draw.PupMenu('No active curve object')
  3544.         return
  3545.     
  3546.     if not IDProp2Prefs(ob.properties, PREFS):
  3547.         if not quiet:
  3548.             Blender.Draw.PupMenu('Curve object has no settings stored on it')
  3549.         return
  3550.     
  3551.     Blender.Draw.Redraw()
  3552.  
  3553. def do_pref_write(e,v):
  3554.     
  3555.     objects = getContextCurveObjects()
  3556.     if not objects:
  3557.         Blender.Draw.PupMenu('No curve objects selected')
  3558.         return
  3559.     
  3560.     for ob in objects:
  3561.         Prefs2IDProp(ob.properties, PREFS)
  3562.     
  3563. def do_pref_clear(e,v):
  3564.     objects = getContextCurveObjects()
  3565.     if not objects:
  3566.         Blender.Draw.PupMenu('No curve objects selected')
  3567.         return
  3568.     
  3569.     for ob in objects:
  3570.         try:    del ob.properties[ID_SLOT_NAME]
  3571.         except:    pass
  3572.  
  3573. def do_tex_check(e,v):
  3574.     if not v: return
  3575.     try:
  3576.         bpy.data.textures[v]
  3577.     except:
  3578.         PREFS['anim_tex'].val = ''
  3579.         Draw.PupMenu('Texture dosnt exist!')
  3580.         Draw.Redraw()
  3581.  
  3582. def do_ob_check(e,v):
  3583.     if not v: return
  3584.     try:
  3585.         bpy.data.objects[v]
  3586.     except:
  3587.         # PREFS['twig_ob_bounds'].val = ''
  3588.         Draw.PupMenu('Object dosnt exist!')
  3589.         Draw.Redraw()
  3590.  
  3591. def do_group_check(e,v):
  3592.     if not v: return
  3593.     try:
  3594.         bpy.data.groups[v]
  3595.     except:
  3596.         # PREFS['leaf_object'].val = ''
  3597.         Draw.PupMenu('dosnt exist!')
  3598.         Draw.Redraw()
  3599.  
  3600. # Button callbacks
  3601. def do_active_image(e,v):
  3602.     img = bpy.data.images.active
  3603.     if img:
  3604.         PREFS['image_main'].val = img.name
  3605.     else:
  3606.         PREFS['image_main'].val = ''
  3607.  
  3608. # Button callbacks
  3609. def do_tree_generate__real():
  3610.     sce = bpy.data.scenes.active
  3611.     objects = getContextCurveObjects()
  3612.     
  3613.     if not objects:
  3614.         Draw.PupMenu('Select one or more curve objects or a mesh/armature types with curve parents')
  3615.     
  3616.     is_editmode = Blender.Window.EditMode()
  3617.     if is_editmode:
  3618.         Blender.Window.EditMode(0, '', 0)
  3619.     Blender.Window.WaitCursor(1)
  3620.     
  3621.     for ob in objects:
  3622.         buildTree(ob, len(objects)==1)
  3623.     
  3624.     if is_editmode:
  3625.         Blender.Window.EditMode(1, '', 0)
  3626.     
  3627.     Blender.Window.RedrawAll()
  3628.     
  3629.     Blender.Window.WaitCursor(0)
  3630.  
  3631.  
  3632. # Profile
  3633. # Had to do this to get it to work in ubuntu "sudo aptitude install python-profiler"
  3634. '''
  3635. import hotshot
  3636. import profile
  3637. from hotshot import stats
  3638. '''
  3639. def do_tree_generate(e,v):
  3640.     
  3641.     do_tree_generate__real()
  3642.     '''
  3643.     prof = hotshot.Profile("hotshot_edi_stats")
  3644.     prof.runcall(do_tree_generate__real)
  3645.     prof.close()
  3646.     s = stats.load("hotshot_edi_stats")
  3647.     s.sort_stats("time").print_stats()
  3648.     '''
  3649.     if GLOBALS['non_bez_error']:
  3650.         Blender.Draw.PupMenu('Error%t|Nurbs and Poly curve types cant be used!')
  3651.         GLOBALS['non_bez_error'] = 0
  3652.         
  3653. def do_tree_help(e,v):
  3654.     url = 'http://wiki.blender.org/index.php/Scripts/Manual/Wizards/TreeFromCurves'
  3655.     print 'Trying to open web browser with documentation at this address...'
  3656.     print '\t' + url
  3657.     
  3658.     try:
  3659.         import webbrowser
  3660.         webbrowser.open(url)
  3661.     except:
  3662.         print '...could not open a browser window.'
  3663.  
  3664.  
  3665. def evt(e,val):
  3666.     pass
  3667.  
  3668. def bevt(e):
  3669.     
  3670.     if e==EVENT_NONE:
  3671.         return
  3672.     
  3673.     if e == EVENT_UPDATE or e == EVENT_UPDATE_AND_UI:
  3674.         if GLOBAL_PREFS['realtime_update'].val:
  3675.             do_tree_generate(0,0) # values dont matter
  3676.     
  3677.     if e == EVENT_REDRAW or e == EVENT_UPDATE_AND_UI:
  3678.         Draw.Redraw()
  3679.     if e == EVENT_EXIT:
  3680.         Draw.Exit()
  3681.     pass
  3682.     
  3683. def gui():
  3684.     MARGIN = 4
  3685.     rect = BPyWindow.spaceRect()
  3686.     but_width = int((rect[2]-MARGIN*2)/4.0) # 72
  3687.     # Clamp
  3688.     if but_width>100: but_width = 100
  3689.     but_height = 17
  3690.     
  3691.     x=MARGIN
  3692.     y=rect[3]-but_height-MARGIN
  3693.     xtmp = x
  3694.  
  3695.     Blender.Draw.BeginAlign()
  3696.     PREFS['do_twigs_fill'] =    Draw.Toggle('Fill Twigs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_twigs_fill'].val,    'Generate child branches based existing branches'); xtmp += but_width*2;
  3697.     if PREFS['do_twigs_fill'].val:
  3698.         
  3699.         PREFS['twig_fill_levels'] =    Draw.Number('Generations',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_levels'].val, 1, 32,    'How many generations to make for filled twigs'); xtmp += but_width*2;
  3700.         y-=but_height
  3701.         xtmp = x
  3702.         
  3703.         # ---------- ---------- ---------- ----------
  3704.         # WARNING USED IN 2 PLACES!! - see below
  3705.         PREFS['twig_ob_bounds'] =    Draw.String('OB Bound: ',    EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_ob_bounds'].val, 64,    'Only grow twigs inside this mesh object', do_ob_check); xtmp += but_width*2;
  3706.         PREFS['twig_fill_rand_scale'] =    Draw.Number('Randomize Scale',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_rand_scale'].val, 0.0, 1.0,    'Randomize twig scale from the bounding mesh'); xtmp += but_width*2;
  3707.         
  3708.         y-=but_height
  3709.         xtmp = x
  3710.         
  3711.         PREFS['twig_fill_radius_min'] =    Draw.Number('Min Radius',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_radius_min'].val, 0.0, 1.0,    'Radius at endpoints of all twigs'); xtmp += but_width*2;
  3712.         PREFS['twig_fill_radius_factor'] =    Draw.Number('Inherit Scale',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_radius_factor'].val, 0.0, 1.0,    'What attaching to branches, scale the radius by this value for filled twigs, 0.0 for fixed width twigs.'); xtmp += but_width*2;
  3713.         
  3714.         y-=but_height
  3715.         xtmp = x
  3716.         
  3717.         #PREFS['twig_fill_shape_type'] =    Draw.Number('Shape Type',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_shape_type'].val, 0.0, 1.0,    'Shape used for the fork'); xtmp += but_width*2;
  3718.         PREFS['twig_fill_shape_type'] =    Draw.Menu('Join Type%t|Even%x0|Smooth One Child%x1|Smooth Both Children%x2',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_fill_shape_type'].val,    'Select the wat twigs '); xtmp += but_width*2;
  3719.         PREFS['twig_fill_fork_angle_max'] =    Draw.Number('Shape Max Ang',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_fork_angle_max'].val, 0.0, 180.0,    'Maximum fork angle'); xtmp += but_width*2;
  3720.         
  3721.         y-=but_height
  3722.         xtmp = x        
  3723.         
  3724.         PREFS['twig_fill_shape_rand'] =    Draw.Number('Shape Rand',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_shape_rand'].val, 0.0, 1.0,    'Randomize the shape of forks'); xtmp += but_width*2;
  3725.         PREFS['twig_fill_shape_power'] = Draw.Number('Shape Strength',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_fill_shape_power'].val, 0.0, 1.0,    'Strength of curves'); xtmp += but_width*2;
  3726.     
  3727.     Blender.Draw.EndAlign()
  3728.     
  3729.     y-=but_height+MARGIN
  3730.     xtmp = x
  3731.     # ---------- ---------- ---------- ----------
  3732.     
  3733.     
  3734.     
  3735.     # ---------- ---------- ---------- ----------
  3736.     Blender.Draw.BeginAlign()
  3737.     PREFS['do_twigs'] =    Draw.Toggle('Grow Twigs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_twigs'].val,    'Generate child branches based existing branches'); xtmp += but_width*2;
  3738.     if PREFS['do_twigs'].val:
  3739.         
  3740.         PREFS['twig_ratio'] =    Draw.Number('Twig Multiply',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_ratio'].val, 0.01, 500.0,    'How many twigs to generate per branch'); xtmp += but_width*2;
  3741.         y-=but_height
  3742.         xtmp = x
  3743.         
  3744.         # ---------- ---------- ---------- ----------
  3745.         PREFS['twig_select_mode'] =    Draw.Menu('Branch Selection Method%t|From Short%x0|From Long%x1|From Straight%x2|From Bent%x3|',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_select_mode'].val,    'Select branches to use as twigs based on this attribute'); xtmp += but_width*2;
  3746.         PREFS['twig_select_factor'] =    Draw.Number('From Factor',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_select_factor'].val, 0.0, 16,    'Select branches, lower value is more strict and will give you less variation'); xtmp += but_width*2;
  3747.         y-=but_height
  3748.         xtmp = x
  3749.         
  3750.         # ---------- ---------- ---------- ----------
  3751.         PREFS['twig_recursive'] =    Draw.Toggle('Recursive Twigs',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_recursive'].val,    'Recursively add twigs into eachother'); xtmp += but_width*2;
  3752.         PREFS['twig_recursive_limit'] =    Draw.Number('Generations',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_recursive_limit'].val, 0.0, 16,    'Number of generations allowed, 0 is inf'); xtmp += but_width*2;
  3753.         y-=but_height
  3754.         xtmp = x
  3755.         
  3756.         # ---------- ---------- ---------- ----------
  3757.         
  3758.         PREFS['twig_scale'] =    Draw.Number('Twig Scale',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_scale'].val, 0.01, 10.0,    'Scale down twigs in relation to their parents each generation'); xtmp += but_width*2;
  3759.         PREFS['twig_scale_width'] =    Draw.Number('Twig Scale Width',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_scale_width'].val, 0.01, 20.0,    'Scale the twig length only (not thickness)'); xtmp += but_width*2;
  3760.         y-=but_height
  3761.         xtmp = x
  3762.         
  3763.         # ---------- ---------- ---------- ----------
  3764.         
  3765.         PREFS['twig_random_orientation'] =    Draw.Number('Rand Orientation',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_random_orientation'].val, 0.0, 360.0,    'Random rotation around the parent'); xtmp += but_width*2;
  3766.         PREFS['twig_random_angle'] =    Draw.Number('Rand Angle',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_random_angle'].val, 0.0, 360.0,    'Random rotation to the parent joint'); xtmp += but_width*2;
  3767.         y-=but_height
  3768.         xtmp = x
  3769.         
  3770.         # ---------- ---------- ---------- ----------
  3771.         
  3772.         PREFS['twig_placement_maxradius'] =    Draw.Number('Place Max Radius',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_placement_maxradius'].val, 0.0, 50.0,    'Only place twigs on branches below this radius'); xtmp += but_width*2;
  3773.         PREFS['twig_placement_maxtwig'] =    Draw.Number('Place Max Count',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['twig_placement_maxtwig'].val, 0.0, 50.0,    'Limit twig placement to this many per branch'); xtmp += but_width*2;
  3774.         
  3775.         y-=but_height
  3776.         xtmp = x
  3777.         # ---------- ---------- ---------- ----------
  3778.         
  3779.         PREFS['twig_follow_parent'] =    Draw.Number('ParFollow',    EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_parent'].val, 0.0, 10.0,    'Follow the parent branch'); xtmp += but_width;
  3780.         PREFS['twig_follow_x'] =    Draw.Number('Grav X',    EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_x'].val, -10.0, 10.0,    'Twigs gravitate on the X axis'); xtmp += but_width;
  3781.         PREFS['twig_follow_y'] =    Draw.Number('Grav Y',    EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_y'].val, -10.0, 10.0,    'Twigs gravitate on the Y axis'); xtmp += but_width;
  3782.         PREFS['twig_follow_z'] =    Draw.Number('Grav Z',    EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['twig_follow_z'].val, -10.0, 10.0,    'Twigs gravitate on the Z axis'); xtmp += but_width;
  3783.         
  3784.         y-=but_height
  3785.         xtmp = x
  3786.         
  3787.         # ---------- ---------- ---------- ----------
  3788.         # WARNING USED IN 2 PLACES!!
  3789.         PREFS['twig_ob_bounds'] =    Draw.String('OB Bound: ',    EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['twig_ob_bounds'].val, 64,    'Only grow twigs inside this mesh object', do_ob_check); xtmp += but_width*2;
  3790.         
  3791.         if PREFS['twig_ob_bounds_prune'].val:
  3792.             but_width_tmp = but_width
  3793.         else:
  3794.             but_width_tmp = but_width*2
  3795.         
  3796.         PREFS['twig_ob_bounds_prune'] =    Draw.Toggle('Prune',EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['twig_ob_bounds_prune'].val,    'Prune twigs to the mesh object bounds'); xtmp += but_width_tmp;
  3797.         if PREFS['twig_ob_bounds_prune'].val:
  3798.             PREFS['twig_ob_bounds_prune_taper'] =    Draw.Number('Taper',    EVENT_UPDATE_AND_UI, xtmp, y, but_width, but_height, PREFS['twig_ob_bounds_prune_taper'].val, 0.0, 1.0,    'Taper pruned branches to a point'); xtmp += but_width;
  3799.         
  3800.         #PREFS['image_main'] =    Draw.String('IM: ',    EVENT_UPDATE, xtmp, y, but_width*3, but_height, PREFS['image_main'].val, 64,    'Image to apply to faces'); xtmp += but_width*3;
  3801.         #Draw.PushButton('Use Active',    EVENT_UPDATE, xtmp, y, but_width, but_height,    'Get the image from the active image window', do_active_image); xtmp += but_width;
  3802.     Blender.Draw.EndAlign()
  3803.     
  3804.     y-=but_height+MARGIN
  3805.     xtmp = x
  3806.     # ---------- ---------- ---------- ----------
  3807.     
  3808.     
  3809.     
  3810.     Blender.Draw.BeginAlign()
  3811.     PREFS['do_leaf'] =    Draw.Toggle('Generate Leaves',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_leaf'].val,        'Generate leaves using duplifaces'); xtmp += but_width*2;
  3812.     
  3813.     if PREFS['do_leaf'].val:
  3814.         
  3815.         PREFS['leaf_object'] =    Draw.String('OB: ',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_object'].val, 64,    'Use this object as a leaf', do_ob_check); xtmp += but_width*2;
  3816.         # ---------- ---------- ---------- ----------
  3817.         y-=but_height
  3818.         xtmp = x
  3819.         
  3820.         PREFS['leaf_size'] =    Draw.Number('Size',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_size'].val, 0.001, 10.0,    'size of the leaf'); xtmp += but_width*2;
  3821.         PREFS['leaf_size_rand'] =    Draw.Number('Randsize',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_size_rand'].val, 0.0, 1.0,    'randomize the leaf size'); xtmp += but_width*2;
  3822.         
  3823.         # ---------- ---------- ---------- ----------
  3824.         y-=but_height
  3825.         xtmp = x
  3826.         
  3827.         # Dont use yet
  3828.         PREFS['leaf_branch_limit'] =        Draw.Number('Branch Limit',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_limit'].val,    0.0, 1.0,    'Maximum thichness where a branch can bare leaves, higher value to place leaves on bigger branches'); xtmp += but_width*2;
  3829.         PREFS['leaf_branch_limit_rand'] =    Draw.Number('Limit Random',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_limit_rand'].val,    0.0, 1.0,    'Randomize the allowed minimum branch width to place leaves'); xtmp += but_width*2;
  3830.         
  3831.         # ---------- ---------- ---------- ----------
  3832.         y-=but_height
  3833.         xtmp = x
  3834.         
  3835.         PREFS['leaf_branch_density'] =    Draw.Number('Density',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_density'].val,    0.0, 1.0,    'Chance each segment has of baring a leaf, use a high value for more leaves'); xtmp += but_width*2;
  3836.         PREFS['leaf_branch_angle'] =    Draw.Number('Angle From Branch',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_angle'].val,    0.0, 90.0,    'angle the leaf is from the branch direction'); xtmp += but_width*2;
  3837.         
  3838.         # ---------- ---------- ---------- ----------
  3839.         y-=but_height
  3840.         xtmp = x
  3841.         
  3842.         PREFS['leaf_rand_seed'] =    Draw.Number('Random Seed',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_rand_seed'].val,    0.0, 10000.0,    'Set the seed for leaf random values'); xtmp += but_width*2;
  3843.         PREFS['leaf_branch_pitch_angle'] =    Draw.Number('Pitch Angle',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_pitch_angle'].val,    -180, 180.0,    'Change the pitch rotation of leaves, negative angle to point down'); xtmp += but_width*2;
  3844.         
  3845.         # ---------- ---------- ---------- ----------
  3846.         y-=but_height
  3847.         xtmp = x
  3848.         
  3849.         PREFS['leaf_branch_pitch_rand'] =    Draw.Number('Random Pitch',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_pitch_rand'].val,    0.0, 1.0,    'Randomize the leaf rotation (up-down/pitch)'); xtmp += but_width*2;
  3850.         PREFS['leaf_branch_roll_rand'] =    Draw.Number('Random Roll',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['leaf_branch_roll_rand'].val,    0.0, 1.0,    'Randomize the leaf rotation (roll/tilt/yaw)'); xtmp += but_width*2;
  3851.         
  3852.     
  3853.     Blender.Draw.EndAlign()
  3854.     
  3855.     y-=but_height+MARGIN
  3856.     xtmp = x
  3857.     # ---------- ---------- ---------- ----------
  3858.     
  3859.     
  3860.     Blender.Draw.BeginAlign()
  3861.     if PREFS['do_uv'].val == 0:    but_width_tmp = but_width*2
  3862.     else:                        but_width_tmp = but_width*4
  3863.     PREFS['do_uv'] =    Draw.Toggle('Generate UVs',EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['do_uv'].val,        'Calculate UVs coords'); xtmp += but_width_tmp;
  3864.     
  3865.     if PREFS['do_uv'].val:
  3866.         # ---------- ---------- ---------- ----------
  3867.         y-=but_height
  3868.         xtmp = x
  3869.         
  3870.         PREFS['do_uv_uscale'] =    Draw.Toggle('U-Scale',    EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['do_uv_uscale'].val,        'Scale the width according to the face size (will NOT tile)'); xtmp += but_width;
  3871.         PREFS['do_uv_keep_vproportion'] =    Draw.Toggle('V-Aspect',    EVENT_UPDATE, xtmp, y, but_width, but_height, PREFS['do_uv_keep_vproportion'].val,        'Correct the UV aspect with the branch width'); xtmp += but_width;
  3872.         PREFS['do_uv_vnormalize'] =    Draw.Toggle('V-Normaize',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_uv_vnormalize'].val,        'Scale the UVs to fit onto the image verticaly'); xtmp += but_width*2;
  3873.         
  3874.         y-=but_height
  3875.         xtmp = x
  3876.         # ---------- ---------- ---------- ----------
  3877.         
  3878.         PREFS['uv_x_scale'] =    Draw.Number('Scale U',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['uv_x_scale'].val,    0.01, 10.0,    'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2;
  3879.         PREFS['uv_y_scale'] =    Draw.Number('Scale V',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['uv_y_scale'].val,    0.01, 10.0,    'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2;
  3880.         
  3881.         y-=but_height
  3882.         xtmp = x
  3883.         # ---------- ---------- ---------- ----------
  3884.         
  3885.         PREFS['image_main'] =    Draw.String('IM: ',    EVENT_UPDATE, xtmp, y, but_width*3, but_height, PREFS['image_main'].val, 64,    'Image to apply to faces'); xtmp += but_width*3;
  3886.         Draw.PushButton('Use Active',    EVENT_UPDATE, xtmp, y, but_width, but_height,    'Get the image from the active image window', do_active_image); xtmp += but_width;
  3887.     Blender.Draw.EndAlign()
  3888.     
  3889.     y-=but_height+MARGIN
  3890.     xtmp = x
  3891.     # ---------- ---------- ---------- ----------
  3892.     
  3893.     Blender.Draw.BeginAlign()
  3894.     PREFS['do_material'] =    Draw.Toggle('Generate Material',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_material'].val,        'Create material and textures (for seamless joints)'); xtmp += but_width*2;
  3895.     
  3896.     if PREFS['do_material'].val:
  3897.         PREFS['material_use_existing'] =    Draw.Toggle('ReUse Existing',EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['material_use_existing'].val,        'Modify the textures of the existing material'); xtmp += but_width*2;
  3898.         
  3899.         # ---------- ---------- ---------- ----------
  3900.         y-=but_height
  3901.         xtmp = x
  3902.         
  3903.         PREFS['material_texture'] =    Draw.Toggle('Texture', EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['material_texture'].val,        'Create an image texture for this material to use'); xtmp += but_width*2;
  3904.         PREFS['material_stencil'] =    Draw.Toggle('Blend Joints',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['material_stencil'].val,        'Use a 2 more texture and UV layers to blend the seams between joints'); xtmp += but_width*2;
  3905.     Blender.Draw.EndAlign()
  3906.     
  3907.     y-=but_height+MARGIN
  3908.     xtmp = x
  3909.     # ---------- ---------- ---------- ----------
  3910.     
  3911.     Blender.Draw.BeginAlign()
  3912.     if PREFS['do_armature'].val == 0:
  3913.         but_width_tmp = but_width*2
  3914.     else:
  3915.         but_width_tmp = but_width*4
  3916.     
  3917.     Blender.Draw.BeginAlign()
  3918.     PREFS['do_armature'] =    Draw.Toggle('Generate Motion',    EVENT_UPDATE_AND_UI, xtmp, y, but_width_tmp, but_height, PREFS['do_armature'].val,    'Generate Armatuer animation and apply to branches'); xtmp += but_width_tmp;
  3919.     
  3920.     # ---------- ---------- ---------- ----------
  3921.     if PREFS['do_armature'].val:
  3922.         y-=but_height
  3923.         xtmp = x
  3924.         
  3925.         PREFS['do_anim'] =    Draw.Toggle('Texture Anim',    EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_anim'].val,    'Use a texture to animate the bones'); xtmp += but_width*2;
  3926.         
  3927.         if PREFS['do_anim'].val:
  3928.             
  3929.             PREFS['anim_tex'] =    Draw.String('TEX: ',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['anim_tex'].val, 64,    'Texture to use for the IPO Driver animation', do_tex_check); xtmp += but_width*2;
  3930.             y-=but_height
  3931.             xtmp = x        
  3932.             # ---------- ---------- ---------- ----------
  3933.             
  3934.             PREFS['anim_speed'] =        Draw.Number('Speed',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['anim_speed'].val,    0.001, 10.0,    'Animate the movement faster with a higher value'); xtmp += but_width*2;
  3935.             PREFS['anim_magnitude'] =    Draw.Number('Magnitude',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['anim_magnitude'].val,    0.001, 10.0,    'Animate with more motion with a higher value'); xtmp += but_width*2;
  3936.             y-=but_height
  3937.             xtmp = x
  3938.             # ---------- ---------- ---------- ----------
  3939.             
  3940.             PREFS['anim_offset_scale'] =    Draw.Number('Unique Offset Scale',    EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['anim_offset_scale'].val,    0.001, 10.0,    'Use the curve object location as input into the texture so trees have more unique motion, a low value is less unique'); xtmp += but_width*4;
  3941.             y-=but_height
  3942.             xtmp = x
  3943.             
  3944.             # ---------- ---------- ---------- ----------
  3945.             
  3946.             PREFS['anim_speed_size_scale'] =    Draw.Toggle('Branch Size Scales Speed',    EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['anim_speed_size_scale'].val,    'Use the branch size as a factor when calculating speed'); xtmp += but_width*4;
  3947.     
  3948.     Blender.Draw.EndAlign()
  3949.     
  3950.     y-=but_height+MARGIN
  3951.     xtmp = x
  3952.     
  3953.     
  3954.     
  3955.     
  3956.     # ---------- ---------- ---------- ----------
  3957.     
  3958.     Blender.Draw.BeginAlign()
  3959.     PREFS['do_variation'] =    Draw.Toggle('Generate Variation',    EVENT_UPDATE_AND_UI, xtmp, y, but_width*2, but_height, PREFS['do_variation'].val,    'Create a variant by moving the branches'); xtmp += but_width*2;
  3960.     
  3961.     # ---------- ---------- ---------- ----------
  3962.     if PREFS['do_variation'].val:
  3963.         PREFS['variation_seed'] =        Draw.Number('Rand Seed',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['variation_seed'].val,    1, 100000,    'Change this to get a different variation'); xtmp += but_width*2;
  3964.         y-=but_height
  3965.         xtmp = x
  3966.         
  3967.         
  3968.         PREFS['variation_orientation'] =        Draw.Number('Orientation',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['variation_orientation'].val,    0, 1.0,    'Randomize rotation of the branch around its parent'); xtmp += but_width*2;
  3969.         PREFS['variation_scale'] =    Draw.Number('Scale',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['variation_scale'].val,    0.0, 1.0,    'Randomize the scale of branches'); xtmp += but_width*2;
  3970.     
  3971.     Blender.Draw.EndAlign()
  3972.     
  3973.     y-=but_height+(MARGIN*2)
  3974.     xtmp = x
  3975.     
  3976.     
  3977.     
  3978.     # ---------- ---------- ---------- ----------
  3979.     Blender.Draw.BeginAlign()
  3980.     PREFS['seg_density'] =    Draw.Number('Segment Spacing',EVENT_UPDATE, xtmp, y, but_width*4, but_height, PREFS['seg_density'].val,    0.05, 10.0,    'Scale the limit points collapse, that are closer then the branch width'); xtmp += but_width*4;
  3981.     
  3982.     y-=but_height
  3983.     xtmp = x
  3984.  
  3985.     # ---------- ---------- ---------- ----------
  3986.     PREFS['seg_density_angle'] =    Draw.Number('Angle Spacing',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_density_angle'].val,    0.0, 180.0,    'Segments above this angle will not collapse (lower value for more detail)'); xtmp += but_width*2;
  3987.     PREFS['seg_density_radius'] =    Draw.Number('Radius Spacing',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_density_radius'].val,    0.0, 1.0,    'Segments above this difference in radius will not collapse (lower value for more detail)'); xtmp += but_width*2;
  3988.     
  3989.     y-=but_height
  3990.     xtmp = x
  3991.     # ---------- ---------- ---------- ----------
  3992.     
  3993.     PREFS['seg_joint_compression'] =    Draw.Number('Joint Width',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_joint_compression'].val,    0.1, 2.0,    'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2;
  3994.     PREFS['seg_joint_smooth'] =    Draw.Number('Joint Smooth',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['seg_joint_smooth'].val,    0.0, 1.0,    'Edge loop spacing around branch join, lower value for less webed joins'); xtmp += but_width*2;
  3995.     
  3996.     y-=but_height
  3997.     xtmp = x
  3998.     # ---------- ---------- ---------- ----------
  3999.     
  4000.     PREFS['connect_sloppy'] =    Draw.Number('Connect Limit',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['connect_sloppy'].val,    0.1, 3.0,    'Strictness when connecting branches'); xtmp += but_width*2;
  4001.     PREFS['connect_base_trim'] =    Draw.Number('Joint Bevel',    EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['connect_base_trim'].val,    0.0, 2.0,    'low value for a tight join, hi for a smoother bevel'); xtmp += but_width*2;
  4002.     Blender.Draw.EndAlign()
  4003.     y-=but_height+MARGIN
  4004.     xtmp = x
  4005.     
  4006.     # ---------- ---------- ---------- ----------
  4007.     Blender.Draw.BeginAlign()
  4008.     PREFS['do_cap_ends'] =    Draw.Toggle('Cap Ends',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_cap_ends'].val,        'Add faces onto branch endpoints'); xtmp += but_width*2;
  4009.     PREFS['do_subsurf'] =    Draw.Toggle('SubSurf',EVENT_UPDATE, xtmp, y, but_width*2, but_height, PREFS['do_subsurf'].val,        'Enable subsurf for newly generated objects'); xtmp += but_width*2;
  4010.     Blender.Draw.EndAlign()
  4011.     y-=but_height+MARGIN
  4012.     xtmp = x
  4013.     
  4014.     
  4015.     # ---------- ---------- ---------- ----------
  4016.     Blender.Draw.BeginAlign()
  4017.     Draw.PushButton('Read Active Prefs',    EVENT_REDRAW, xtmp, y, but_width*2, but_height,    'Read the ID Property settings from the active curve object', do_pref_read); xtmp += but_width*2;
  4018.     Draw.PushButton('Write Prefs to Sel',    EVENT_NONE, xtmp, y, but_width*2, but_height,    'Save these settings in the ID Properties of all selected curve objects', do_pref_write); xtmp += but_width*2;
  4019.  
  4020.     y-=but_height
  4021.     xtmp = x
  4022.     
  4023.     # ---------- ---------- ---------- ----------
  4024.     Draw.PushButton('Clear Prefs from Sel',    EVENT_NONE, xtmp, y, but_width*4, but_height,    'Remove settings from the selected curve aaobjects', do_pref_clear); xtmp += but_width*4;
  4025.     Blender.Draw.EndAlign()
  4026.  
  4027.     y-=but_height+MARGIN
  4028.     xtmp = x
  4029.     # ---------- ---------- ---------- ----------
  4030.     
  4031.     Blender.Draw.BeginAlign()
  4032.     Draw.PushButton('Exit',    EVENT_EXIT, xtmp, y, but_width, but_height,    ''); xtmp += but_width;
  4033.     Draw.PushButton('Help',    EVENT_NONE, xtmp, y, but_width, but_height,    '', do_tree_help); xtmp += but_width;
  4034.     Draw.PushButton('Generate from selection',    EVENT_REDRAW, xtmp, y, but_width*2, but_height,    'Generate mesh', do_tree_generate); xtmp += but_width*3;
  4035.     Blender.Draw.EndAlign()
  4036.     y-=but_height+MARGIN
  4037.     xtmp = x
  4038.     # ---------- ---------- ---------- ----------
  4039.     
  4040.     GLOBAL_PREFS['realtime_update'] =    Draw.Toggle('Automatic Update',    EVENT_UPDATE, xtmp, y, but_width*4, but_height, GLOBAL_PREFS['realtime_update'].val,    'Update automatically when settings change'); xtmp += but_width*4;
  4041.     
  4042.     
  4043.  
  4044. if __name__ == '__main__':
  4045.     # Read the active objects prefs on load. if they exist
  4046.     do_pref_read(quiet=True)
  4047.     
  4048.     Draw.Register(gui, evt, bevt)
  4049.